On Fri, Apr 21, 2023 at 6:02 AM Rowan Tommins <rowan.coll...@gmail.com>

> Hi Marco!
> I'll come back to type aliases in a second, but first:
> > can `function bar() {}` be a symbol?
> It already is. When you run foo('bar'), PHP has to look up what the
> definition of "foo" is in a table of functions. In principle,
> autoloading could work for those just the same way it does for classes
> ... except for one awkward feature which seemed like a good idea 15
> years ago. If you write this:
> namespace Foo {
>      echo strlen('hello');
> }
> Should PHP lookup the function "\Foo\strlen", or the function "\strlen"?
> The "clever" answer 15 years ago was to do *both*: try the namespaced
> name first, then if it doesn't exist, try the global name. This does not
> happen for classes, only for functions and constants.
> This is a real pain for autoloading: how do you avoid repeatedly calling
> the autoloader looking for "\Foo\strlen", finding there's still no
> definition, and falling back to "\strlen"? That's one of the main points
> of discussion whenever function autoloading comes up.
This is super interesting, thank you for the info. I guess maybe I'm a bit
naive on why there would be controversy here. I see it kind of like this:

- PHP looks up \Foo\strlen. It's not on the Symbols table. Trigger autoload
for it.
- Autoload finds a definition, register it on the Symbols table and execute

I'm guessing this already works today. Now let's see the other case:

- PHP looks up \Foo\strlen. It's not on the Symbols table. Trigger autoload
for it.
- Autoload does NOT find a definition, register in the Symbols table that
\Foo\strlen is undefined.
- PHP looks up \strlen. It's not on the Symbols table, trigger autoload for
- Autoload finds a definition, registers in the Symbols table and executes

Since \Foo\strlen already had an autoload execution, it already had a
chance to be loaded, if it wasn't we can "cache" that result. However, if
the script is doing something crazy, we can let the definition of
`\Foo\strlen` be overwritten if it ever gets "naturally discovered as a
symbol". That is, if you e.g. try to use a class \Foo\Bar and autoloading
loads the file ./foo/Bar.php and inside that file there is a definition for
`\Foo\strlen`, even though `\Foo\strlen` has already been written as
"undefined", the Symbols table could overwrite the "undefined" value
instead of crashing with "\Foo\strlen already exists".

This wouldn't go against PHP's core nature and it would avoid triggering an
autoload for the same function over and over again even though it's
naturally expected that it will not exist.

I can imagine one would argue that caching every native function with a
huge amount of namespace with a "undefined" definition could take up some
memory space, but wouldn't that just encourage the PHP Community, PHP IDEs
and static analysers to promote top-level file `use function \strlen`,
avoid the recursive trial-and-error and avoid registering many namespaces
and consuming more memory? It's already natural (and not just in PHP) for
IDEs to just hide the entire import statement block, so :shrug:

Here at least I can understand why it's a bit controversial. The obvious
solution to me might not be an acceptable take for other people and it's
somewhat understandable.

> > Can `type Number = int|number;` be a symbol?
> > Can `type TwoInts = callable(int $x, int $y): int;` be a symbol?
> Fundamentally, yes. They'd probably need to occupy the same lookup table
> as classes - if I write "function foo(SomeType $someArg)", PHP doesn't
> know until it's looked it up whether "SomeType" is a type alias or class
> - but that's not a big problem.
> I think there is some discussion around whether people *want* it to work
> that way - should it be more like a "use" statement, and just take
> effect for the current file? Then there's questions around how to
> actually implement it, and do so efficiently. But creating a table of
> names to types isn't the hard part of the problem.

>From Rob's email (https://externals.io/message/120094#120097), the argument
against a simple "use" statement seems quite natural. I certainly don't
want to redefine "use int|float as Number" in every PHP file I work with,
so naturally we would go back to type alias definition, symbol registration
and autoloading. So I guess my final question is: what is fundamentally
different about Type Alias when compared to interfaces, classes, enums that
make this controversial?

Marco Deleu

Reply via email to