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