On Thu, Mar 6, 2025, at 00:11, Rob Landers wrote:
> Hello PHP Internals,
>
> I'd like to introduce my RFC for discussion: https://wiki.php.net/rfc/short-and-inner-classes
>
> This RFC defines a short class syntax as well as the ability to nest classes inside another
> class. This introduces an unprecedented amount of control, flexibility, and expressiveness over how
> objects are used and instantiated in PHP. There is a PR (https://github.com/php/php-src/pull/17895)
> that implements this functionality -- all test failures are related to different/new/incorrect error
> messages being generated. However, the core functionality exists to take for a test ride.
>
> So, what do I mean by "unprecedented amount of control"? With this change, you can
> declare an inner class as private or protected, preventing its usage outside of the outer class:
>
> class User {
> private class Id {}
>
> public function __construct(public self::Id $id) {}
> }
>
> In the above example, the class User
is impossible to construct even though it has
> a public constructor (except through reflection) because User::Id is private; User::Id cannot be
> instantiated, used as a type hint, or even via instanceof
outside of the User class
> itself. This example isn't practical but demonstrates something that is nearly impossible in
> previous versions of PHP, where all classes are essentially publicly accessible from anywhere within
> the codebase.
>
> As a number of inner classes will probably be used as DTOs, the RFC introduces a "short
> syntax" for declaring classes, which enhances expressiveness, even allowing the usage of
> traits, all in a single line:
>
> // declare a readonly Point, that implements Vector2 and uses the Evolvable trait
> readonly class Point(public int $x, public int $y) implements Vector2 use Evolvable;
>
> When combined with inner classes, it looks something like this:
>
> class Pixel {
> public readonly class Point(public int $x, public int $y) implements Vector2 use Evolvable;
> }
>
> // Create a new pixel point with property $x and $y set to 0
> $p = new Pixel::Point(0, 0);
>
> There are far more details in the RFC itself, so please check it out. I'm quite excited to
> hear your thoughts!
>
> — Rob
>
> PS. I know I tend to rush into things, but I want to make it clear that I'm not rushing
> this -- I've learned from my mistakes (thank you to those who have given me advice). I'm
> going to do this right.
>
>
Hello internals,
I've made some major updates to the text of the RFC to clarify behaviors and revisited the
implementation (which is still under development, though I hope to have a draft by the end of this
weekend). Here's a broad overview of what has changed in inner classes:
- Accessing inner classes is done via a new token: ":>" instead of "::".
- Inner classes may now be infinitely nested.
- Inner classes may be declared abstract
.
- Documented changes to ReflectionClass.
- Usage of static
to refer to inner classes is restricted to prevent accidental
violations of LSP.
Otherwise, there are not any big changes, but a lot of time was spent clarifying behavior and
expanding on the reasoning for those decisions in the RFC itself.
— Rob