On Fri, Jan 3, 2020 at 2:51 AM tyson andre <tysonandre...@hotmail.com> wrote:
> After a quick search, it turns out I've mostly reinvented > https://wiki.php.net/rfc/autofunc which I hadn't remembered. > The `spl_autoload_*()` changes it mentions is what I had in mind > > There's been changes to php since then, it's been 7 years, > and this adds thoughts on some implementation details. > > It's possible to support function / const autoloading > in a way that keeps existing performance. > Some of the objections at the time no longer apply. > > - `SOME_CONSTANT` no longer falls back to the literal string in php 8. > It throws an Error. > - APC (used by some implementations) is no longer supported. > - Many of the objections were against the available implementations > based on `function __autoload()`, not the concept of autoloading. > > https://www.mail-archive.com/internals@lists.php.net/msg52307.html > - There wasn't much traction from leads for the concept > or a Proof of Concept to vote on for that RFC (I think). > > What if an ambiguous `function_name()` or const outside the global > namespace would attempt to autoload functions in the global namespace > if it would throw an Error, but not the current namespace? > > `function_exists()` or `defined()` would not autoload, > to preserve the behavior/performance of current programs. > Anything with the callable type hint (e.g. `array_map`) would also need to > be modified, > but I think it already needs to do that for method arrays and > 'MyClass::method'. > > - Same for global constants > - That should avoid the performance hit - this autoloading would only be > triggered > when php would previously throw an Error or warning > for undefined functions/constants. > - This would also avoid the need to load polyfill files (e.g. mbstring) > or test framework files when their functions/constants are unused. > - One blocker for other autoload proposals > seemed to be performance if I understood correctly > (e.g. attempting to autoload NS\strlen() every time strlen was called). > > https://externals.io/message/54425#54616 and > https://externals.io/message/54425#54655 > detail this - choosing a different order of checks avoids the > performance hit. > - In addition to the RFC, changing the signatures to `defined(string > $name, bool $autoload = false)` > and `function_exists($name, bool $autoload = false)` > might be useful ways to allow users to choose to autoload when checking > for existence. > > And there'd have to be a hash map, flag, or other check > to avoid recursion on the same constant/function. > > Background: A function call or constant usage is > ambiguous if it could look for the function in two namespaces, > as described by the rules documented in the below link. > It's unambiguous if it ends up looking in only one namespace. > > https://www.php.net/manual/en/language.namespaces.rules.php > The only type of ambiguous function call or global constant use is (7.): > > > 7. For unqualified names, > > if no import rule applies and the name refers to a function or > constant > > and the code is outside the global namespace, the name is resolved at > runtime. > > Assuming the code is in namespace A\B, here is how a call to function > foo() is resolved: > > 1. It looks for a function from the current namespace: A\B\foo(). > > 2. It tries to find and call the global function foo(). > > My approach should be in line with the current name resolution > for unqualified names outside the global namespace. > > 1. It (first) looks for a function from the current namespace: A\B\foo(). > 2. It (next) tries to find and call the global function foo(). > 3. (Optional) NEW ADDITION: Next, if both functions were undefined, > the autoloader(s) attempt to autoload the function A\B\foo() > (and call it instead of throwing if found) before proceeding to step > (4.) > 4. NEW ADDITION: If both functions were undefined, > the autoloader(s) attempt to autoload the global function foo() > (and call it instead of throwing if found) before throwing an Error > > And for unambiguous calls, find and autoload the only name it has. > > The fact that one of the two possible functions gets cached by the php VM > in CACHED_PTR > (for the lifetime of the request) the first time the function is found > in either namespace will remain unchanged with this proposal. > I believe the problem here is this: The fact that the global function is being cached, and continues to be cached when a namespaced function is later defined, is a bug. See for example https://bugs.php.net/bug.php?id=64346. We've never prioritized fixing this issue, but implementing the proposed autoloading behavior would make fixing it essentially impossible, as we certainly can't perform an autoloader invocation on each call. Nikita