On Wed, Dec 3, 2025, at 16:51, Larry Garfield wrote:
Thanks, Rob! This does seem like a good low-hanging fruit piece to attack. Most importantly, I don’t see anything here that would preclude more formal TypeDef structures in the future.
A few other notes:
- Should
mixed be allowed as in an alias definition? Since mixed matches anything, it would render the entire alias redundant as it’s then equivalent to mixed.
This is already a compiler error: “Type mixed can only be used as a standalone type.” That being said, I guess this could be used to rename “mixed” to something else, but I don’t know why you’d want to do that. I’d be open to throwing it in with “never” and “void”, but “mixed” is an actual type that can be returned, which is why it wasn’t.
- What if any conflict resolution is there if you include two different type files that declare the same alias?
It works the same as use in other ways:
“Cannot use type DateTimeImmutable as DT because the name is already in use”
- Because it’s all compile time, I assume two aliases with the same source but different names become compatible?
Eg:
use type string|Stringable as Stringy;
use type string|Stringable as Stringish;
Those are mutually compatible in practice, yes?
That’s correct. You’d need typedefs to be able to enforce a difference there.
- Are aliases case sensitive? You’re using Capitalized names in the RFC, but I don’t know if that means anything… (Please state in the RFC.)
Good catch; will do. For the record, it’s as type-sensitive as any other type in PHP (as in not case-sensitive at all).
- The “include type” syntax implies that it would not be possible to pre-load aliases via Composer autoload or opcache preloading. (Well, maybe the latter.) That feels like an unnecessary limitation, and is my main issue with the current design. Some way to have project-wide or package-wide definitions would be very helpful, without needing a manual include statement in every file.
Currently, we don’t have packages or even “real” namespaces, so as much as I’d want this, there’d need to be some settling on what authority a namespace really has. The amount of pushback that I got on the namespace-private RFC indicates to me that people don’t want namespaces to have any authority, but they want “packages” but nobody knows what a package is … but clearly, namespaces aren’t anything.
I digress. Sadly, no, this isn’t possible with the current design. That doesn’t mean it can’t be possible in the future, though, with some autoloading overhaul or changes (see: Gina’s Core Autoloading RFC under Drafts). But currently, it has to pull off some shenanigans to compile the file in the file (instead of during runtime like require and include). Hence why type-files may only contain types and no other code.
Basically, we just have to have some way to tell the compiler “also include these type aliases when compiling this file” – that could be “every file from here on out gets the aliases” (ie, a use global type float|int as Number – or something like that), or “include this type file” into this source file.
The former would work best with today’s current autoloader, but it would be “trapped” in that paradigm and would make it harder to eventually create a “type autoloader”. I could be wrong, though, and I’m open to other people’s ideas and opinions. I don’t like the current implementation very much, and while the former is much simpler to implement, I’m reasonably confident the current implementation can be improved.
- Does it matter where the
include type statement goes? Must it be at the top under the use statements, or could it be anywhere?
It’s basically a “copy this file right here”, so it doesn’t need to necessarily be at the top, but trying to include it in a function would create a syntax issue. I should clarify this in the RFC.
- Not allowing
use statements in type include files: This feels like a very unfortunate limitation. Is there any way to obviate that? It’s all compile time, as you said…
I had to go make sure I didn’t have a typo in there. I assume you mean namespaces? Namespaces in type files have a very weird problem once they get included. For instance, namespaces are also compile-time prefixes, and using statements are per namespace, not per file. By eliminating the namespace, it becomes unambiguous that it’s per-file. That prevents shenanigans like:
// my-types.php
namespace Hello {
use int|float as Number; // at the end of the namespace, the "use" is lost
}
namespace World {
use Number as Foo; // Number isn't a thing, neither is Hello\Number
}
Even just declaring a namespace for resolving types would create interesting effects:
// my-types.php
namespace Foo;
use int|float as Number;
// alias actually becomes Foo\Number and gets cleared at the end of the file
In all reality, I generally expect tooling to make this easier. Like right-click the alias in your IDE and select: “move to type file” or something like that and have it automatically appended to your project’s type file. Same with typing a type in a type file and having it automatically include it, just like it will automatically “use” a type outside of the current namespace for you.
Overall, I am tentatively in favor.
–Larry Garfield
Thanks!
— Rob