On Mon, Mar 17, 2025, at 16:30, fennic log wrote:
>
> On Wed, 5 Mar 2025 at 23:14, Rob Landers <[email protected]> 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.
>
> I have read and reread this RFC, and I am struggling to see
>
> 1. What problem does this solve that anonymous classes <https://www.php.net/manual/en/language.oop5.anonymous.php>
> do not?
Thank you for asking this question. :) Anonymous classes can be useful to "hack your way
around" the problem that inner (nested?) classes solve. Anonymous classes are inline, leading
to complex/long functions that would do nothing but define a class. Anonymous classes can (could?)
be hacked to allow for reuse (extending), but only exist where they are defined. An inner class can
be extended and reused just fine. Finally, nested classes allow for more readable code without
sacrificing encapsulation.
> 2. As with any syntax change and new operator there needs to be very careful consideration, do
> we need a new operation, or could ::
if the parent is static or ->
if
> the class is initialized?
There's quite a long thread already about this very topic. That being said, the inner class has
no bearing on whether the outer class is instantiated or not. Originally, I used ::
as
the separator, but it seems there are some good arguments for \
, so we will see.
> 3. The idea that extending the parent class doesnt no inherit the child classes doesnt make
> sense to me.
> As then if you extend a parent class and call a function of that class which could rely on the
> existence of an inner class, I can see a lot of headaches caused by this exact scenario.
> As a developer, if I extend a class, I expect the entire dependance of that class to be
> inherited, otherwise the extending class won't work.
I'm not sure what you mean. When you inherit a class, you do not necessarily inherit everything
from its superclass. You are free to override it however you want. Since we are defining
"types" in the sense of PHP, we cannot merely inherit a "type", otherwise we
would cause all kinds of issues with LSP. This is specifically why inheritance works the way it does
in this RFC and why static::
is forbidden.
— Rob