Re: function autoloading v4 RFC
| From: | Rob Landers | Date: | Thu, 15 Aug 2024 22:41:52 +0000 |
| Subject: | Re: function autoloading v4 RFC | ||
| References: | 1 2 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-124963@lists.php.net to get a copy of this message | ||
On Thu, Aug 15, 2024, at 20:40, Rowan Tommins [IMSoP] wrote:
> On 15/08/2024 16:22, Rob Landers wrote:
>> Hello internals,
>>
>> I've decided to attempt an RFC for function autoloading. After reading hundreds of
>> ancient (and recent) emails relating to the topic along with several abandoned RFCs from the past,
>> and after much review, I've decided to put forth a variation of a previous RFC, as it seemed
>> the least ambitious and the most likely to work:
>>
>> https://wiki.php.net/rfc/function_autoloading4
>
>
> Hi Rob,
>
> While brevity can sometimes be a virtue, I feel like there's a lot left to the
> reader's interpretation here.
>
> Specifically, one of the main issues that has come up in previous discussions of the topic is
> the behaviour of unqualified function names, which check the current namespace first, then fall back
> to global scope. Your RFC implies an approach to this, but doesn't actually spell it out, nor
> discuss its pros and cons.
>
It doesn't go too much into details here on purpose, especially since there was some recent
discussion on changing the order. That being said, while writing the reply below, I realized it
simply wasn't clear enough. I've updated the RFC to be more clear, in regards to the
current behavior.
> The fully qualified case is straight-forward: the autoloader is called, and if still not
> defined, an error is thrown. But for the unqualified case, there are multiple scenarios, and you
> only give the behaviour for one of them:
>
To fill in your chart:
> Defined in current namespace? | Defined in global namespace? | Proposed behaviour
>
> ------------------------------+------------------------------+--------------------------------------
> No | No | Prefixed name
> No | Yes | Prefixed name
> Yes | No | No change
> Yes | Yes | No change
>
> The third and fourth cases (where the function exists in the current namespace) are
> straight-forward, although it wouldn't hurt to spell them out: presumably, the namespaced
> function is used as now, so no autoloading is needed.
>
> The complex case has always been the second one: the function doesn't exist in the current
> namespace, but *does* exist in the global namespace.. (Or, an autoloader *defines* it in the global
> namespace.)
>
This should have the same behavior as in the class autoloader. In my attempt to be vague (in case
the loading order is changed, which I assumed would affect class autoloading as well), I wasn't
very clear on this. Meaning if you create a class called "Fiber" and a function called
"strlen" in the current namespace, in unloaded files, an autoloader should be given the
opportunity to load them.
I should also probably define some vocabulary so this is all less confusing. and Done.
> In concrete terms, what does this code output:
>
> spl_autoload_register( function($function, $type) { echo "$function..."; },
> type:SPL_AUTOLOAD_FUNCTION);
>
> namespace Foo {
> foreach (['hello', 'goodbye'] as $word) {
> echo strlen($word), ';';
> }
> }
>
> a) "Foo\strlen...5;Foo\strlen...7;" (the autoloader is called every time the function
> is encountered)
> b) "Foo\strlen...5;7;" (the autoloader is called once, then somehow marked not to run
> again for this name
> c) "5;7;" (the autoloader is never run for this code)
>
I believe the "most correct" answer is (a) -- and is what the current class autoloader
does as well. Option (b) would make it impossible to do any kind of dynamic code generation or
old-fashioned file-based deployments.
namespace global {
spl_autoload_register(function ($function) {
echo "$function...";
});
}
namespace Foo {
foreach (['hello', 'goodbye'] as $word) {
if (!class_exists(Fiber::class)) {
echo "Test...";
}
}
}
Since I foresee (based on previous conversations) about people being worried about performance:
I think this is best left to autoloader authors to manage. If there isn't a function
autoloader, then there won't be any performance impact (or at least, minimal). However, if
there is one, the author can take into account how their codebase works. For example, I highly
suspect FIG will create a PSR for this (eventually), based on how they expect things to work. I
suspect a project like WordPress could make use of it and implement things how they expect things to
work, etc.
For the case where you have a file full of unqualified
strlen()'s, the autoloader
author could create an option "do not shadow global functions" where it just returns
immediately for built-in functions and doesn't even try autoloading (I also suspect there will
be someone who code-golfs this to death so this check is extremely efficient). Is there a
performance impact there? Probably not as big as you'd think -- and there already is a
performance impact by using unqualified global functions (as shown in a recent proposal to change
the order). So, if you are doing that already; you likely don't care about performance anyway.
But I'm going to reserve any serious discussions about performance for when I have an actual
implementation to play with (hopefully a PoC this weekend).
> Note that there is an open RFC implementing option (b) by Gina and Dan here:
> https://wiki.php.net/rfc/core-autoloading Last I heard, Gina was
> still hoping to get back to it.
>
I went looking for this (I had sworn I had seen it last year), but unfortunately, I did not find it
while searching the RFCs for prior work. I had thought it abandoned so I was looking in the wrong
place. This RFC does not conflict with that RFC, if Gina/Dan were to pick it back up again.. I may
borrow the function_exists() change, which I just updated the RFC to do.
> On a different note, there is no mention of autoloading namespaced constants in this RFC,
> unlike in some previous proposals. Is this a conscious decision to leave them out of scope, or an
> oversight?
>
I'm leaving them out on purpose to keep the scope tight. I've got a whole year ahead of
me.
>
>
> Regards,
>
> --
> Rowan Tommins
> [IMSoP]
— Rob