On Thu, Mar 6, 2025, at 23:20, Ilija Tovilo wrote:
> Hi Rob
> 
> On Thu, Mar 6, 2025 at 12:14 AM Rob Landers <rob@bottled.codes> wrote:
> >
> > I'd like to introduce my RFC for discussion: 
> > https://wiki.php.net/rfc/short-and-inner-classes
> 
> Thank you for your proposal.
> 
> I'm very much against the idea of introducing yet another slightly
> shorter form to declare a class. In your examples (they have been
> removed in the meantime), it's unclear how the syntax interacts with
> inherited constructors, trait-used constructors, whether repetition of
> readonly parent properties leads to a "Cannot modify readonly
> property" error, etc.
> 
> The concept of visibility for classes does seem useful to me. Some
> questions that crossed my mind when reading the proposal:
> 
> > Inner classes may only be nested one level deep, may not be a parent class, 
> > and may not be declared abstract
> 
> These restrictions seem somewhat arbitrary. For example, you may want
> a private class to extend another private class, creating some local
> class hierarchy. I think there's value in relaxing this restriction,
> if technically possible.

They're not 100% arbitrary, but mostly due to technical limitations.

- One level deep: Nesting multiple levels results in ambiguous grammar.
- As a parent class: This also results in ambiguity.
- Abstract: If it cannot be a parent class, it doesn't make sense for it to be 
abstract.

> 
> > PHP Fatal error:  Private inner class Box::Point cannot be used in the 
> > global scope
> 
> How is this implemented? I presume using a public nested class as type
> hints should be allowed, but these classes may not be loaded when the
> function is declared. We implement delayed variance checks for
> methods, which do trigger the autoloader, but functions do not (since
> they cannot violate variance rules).

This happens at run time, when the function is called. I believe we can 
guarantee that it will pass/fail with one of the following cases:

- The type check passes and everything is fine
- The type check fails (due to not being the correct type); autoloading never 
happens
- The type check succeeds, but it is private/protected; to have an object of 
that type, you'd have to have loaded the outer class.

This is no different than having:

function foo(MadeUpClass $c) {}

and then never calling foo.

> 
> > Visibility Rules: Private and protected inner classes are only instantiable 
> > within their outer class (or subclasses for protected) and cannot be used 
> > as type declarations outside their outer class. This encapsulation ensures 
> > that the inner class’s implementation details remain within their intended 
> > scope.
> 
> This introduces a weird case where methods with parameter or return
> types referring to private classes may not be redeclared in their
> subclasses, given that the type cannot be specified, even if the
> methods themselves are not private or final. You do mention something
> very similar in your e-mail with the __constructor case, but I really
> fail to see how this provides any benefit.

Yes. This is correct and inline with other languages with inner types. The idea 
behind it is to encapsulate behavior and hide information. The idea is that 
external code should not know anything about the internal structure. This 
grants control over inheritance, which you pointed out, though it is better to 
use final to do that. However, it could be useful if you wanted to create a 
class meant to be inherited (such as a url parser) but prevent modification to 
important methods via inheritance.

> 
> I would also like to echo what has been said about the :: operator,
> which feels out of place. I understand that \ comes with additional
> autoloading challenges, namely requiring a fallback autoloading
> strategy that currently does not conform to PSR-4.

It felt natural to me at the time, but I suspect there may be a better 
nomenclature; we just need to discover it.

> 
> Disclaimer: I have not looked at the implementation at all yet.
> 
> Ilija
> 

— Rob

Reply via email to