Final anonymous classes

php.internals

Daniil Gentili

3 years ago
Hi all, I've submitted https://github.com/php/php-src/pull/11126 to add support for final anonymous classes, though as noted by iluuu1994, it would probably make more sense to just make all anonymous classes final by default, what do you think? Daniil Gentili.

Claude Pache

3 years ago
> Le 24 avr. 2023 à 12:28, Daniil Gentili <daniil@daniil.it> a écrit : > > Hi all, > > I've submitted https://github.com/php/php-src/pull/11126 to add support for final anonymous classes, though as noted by iluuu1994, it would probably make more sense to just make all anonymous classes final by default, what do you think? > > Daniil Gentili. >
Hi, Extending an anonymous class is indeed possible (https://3v4l.org/pDFTL), but it is a hack as best. If someone wants a non-final class, could they not write a non-anonymous one? As a bonus, they wouldn’t need to instantiate the class before referencing it. —Claude

Ilija Tovilo

3 years ago
Hi Claude
> > Hi all, > > > > I've submitted https://github.com/php/php-src/pull/11126 to add support for final anonymous classes, though as noted by iluuu1994, it would probably make more sense to just make all anonymous classes final by default, what do you think? > > Extending an anonymous class is indeed possible (https://3v4l.org/pDFTL), but it is a hack as best. If someone wants a non-final class, could they not write a non-anonymous one? As a bonus, they wouldn’t need to instantiate the class before referencing it.
Indeed. The argument was that, if you need to give the anonymous class a dedicated name through an alias to extend it, you might as well declare a named class in the first place. In case somebody finds benefit in making anonymous classes open, it seems more sensible to make them opt into openness, rather than applying this behavior to all anonymous classes that are used as final 99.9% of the time. Although I really don't think that is necessary. Ilija

Nicolas Grekas

3 years ago
Hi all,
> > I've submitted https://github.com/php/php-src/pull/11126 to add support > for final anonymous classes, though as noted by iluuu1994, it would > probably make more sense to just make all anonymous classes final by > default, what do you think? > > > > Extending an anonymous class is indeed possible (https://3v4l.org/pDFTL), > but it is a hack as best. If someone wants a non-final class, could they > not write a non-anonymous one? As a bonus, they wouldn’t need to > instantiate the class before referencing it. > > Indeed. The argument was that, if you need to give the anonymous class > a dedicated name through an alias to extend it, you might as well > declare a named class in the first place. > > In case somebody finds benefit in making anonymous classes open, it > seems more sensible to make them opt into openness, rather than > applying this behavior to all anonymous classes that are used as final > 99.9% of the time. Although I really don't think that is necessary. >
Fun fact: I wrote test code that extends anonymous classes recently. The typical test case is like this: $obj = new class() { public array $foo; }; $proxy = $this->createLazyGhost($obj::class, fn () => null); And createLazyGhost() generates a proxy class and returns an instance of it, see https://github.com/symfony/symfony/blob/1f8c5928a1445378eacbaf5b7e1636fdfa8610ed/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php#L415-L438 Admittedly this is for convenience in writing test cases, but convenience is what many RFCs are about :) But anyway, there is a related idea I've had in my mind about anonymous classes that I'd like to throw in that conversation: Because they conceptually don't create a new type, I wonder if (final) anonymous classes could be allowed to extend final classes? In order to not allow hacking around and still create a type with class_alias(), we should forbid aliasing final anonymous classes IMHO. Then we could have this discussion about allowing finally anonymous classes to extend final classes. That'd be really useful in many situations where "final" is preventing end users from achieving what they want. Nicolas

Claude Pache

3 years ago
> Le 25 avr. 2023 à 15:46, Nicolas Grekas <nicolas.grekas+php@gmail.com> a écrit : > >  > Because they conceptually don't create a new type, I wonder if (final) > anonymous classes could be allowed to extend final classes? In order to not > allow hacking around and still create a type with class_alias(), we should > forbid aliasing final anonymous classes IMHO. Then we could have this > discussion about allowing finally anonymous classes to extend final > classes. That'd be really useful in many situations where "final" is > preventing end users from achieving what they want.
That would violate the very definition of `final`, which may be interpreted as “final implementation” as much as “final type”? If your goal is to have a proxy, I wonder whether it would be more appropriate to design a proper way to define a proxy around an existing object, rather than hacking around class inheritance? —Claude

Larry Garfield

3 years ago
On Tue, Apr 25, 2023, at 1:21 PM, Ilija Tovilo wrote:
> Hi Claude > >> > Hi all, >> > >> > I've submitted https://github.com/php/php-src/pull/11126 to add support for final anonymous classes, though as noted by iluuu1994, it would probably make more sense to just make all anonymous classes final by default, what do you think? >> >> Extending an anonymous class is indeed possible (https://3v4l.org/pDFTL), but it is a hack as best. If someone wants a non-final class, could they not write a non-anonymous one? As a bonus, they wouldn’t need to instantiate the class before referencing it. > > Indeed. The argument was that, if you need to give the anonymous class > a dedicated name through an alias to extend it, you might as well > declare a named class in the first place. > > In case somebody finds benefit in making anonymous classes open, it > seems more sensible to make them opt into openness, rather than > applying this behavior to all anonymous classes that are used as final > 99.9% of the time. Although I really don't think that is necessary. > > Ilija
I agree, but that would then require adding some kind of "non-final" keyword for anon classes to opt back out of finalness. That's an extra complication I don't see as worth the effort to think through. Until this thread it hadn't even occurred to me that you could extend an anon class at all, so the issue never came up. And the apparent way to do so involves eval(), so I'm already afraid of it. Given how edge-casey this is, I'd be inclined to just leave it be. --Larry Garfield

Unnamed Person

3 years ago
On 24-4-2023 12:28, Daniil Gentili wrote:
> Hi all, > > I've submitted https://github.com/php/php-src/pull/11126 to add > support for final anonymous classes, though as noted by iluuu1994, it > would probably make more sense to just make all anonymous classes > final by default, what do you think? > > Daniil Gentili. >
I always though anonymous class where `final` by nature. The fact that that hack to extend them works, seems iffy at best. For what it's worth, I'd be in favour of making the default behaviour for anonymous classes `final` without the need to add a `final` keyword. For those edge-cases which would be broken by that change, I wonder if support to opt-out could be added via an `#[AllowAliasing]` attribute ?

Derick Rethans

3 years ago
On Mon, 24 Apr 2023, Daniil Gentili wrote:
> I've submitted https://github.com/php/php-src/pull/11126 to add > support for final anonymous classes, though as noted by iluuu1994, it > would probably make more sense to just make all anonymous classes > final by default, what do you think?
Yes. cheers, Derick

Unnamed Person

3 years ago
I am not sure about making them final by default. I think it's a more consistent language design to allow `new final class()` as you originally proposed. Although I don't know why anyone would want to extend anonymous classes, we can see that people do, in fact, do it. I don't see why we couldn't allow `new class() extends $someClass` in the future to specifically allow them to do this. I mean, I'm not going to lobby for it, I'm just pointing out that is more aligned and consistent with other parts of the language, than to simply make it final by default. Cheers.

Rokas Šleinius

3 years ago
On Fri, 5 May 2023 at 23:58, Levi Morrison via internals <internals@lists.php.net> wrote:
> > I am not sure about making them final by default. I think it's a more > consistent language design to allow `new final class()` as you > originally proposed. Although I don't know why anyone would want to > extend anonymous classes, we can see that people do, in fact, do it. I > don't see why we couldn't allow `new class() extends $someClass` in > the future to specifically allow them to do this. I mean, I'm not > going to lobby for it, I'm just pointing out that is more aligned and > consistent with other parts of the language, than to simply make it > final by default. > > Cheers. > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >
My work currently is integrating with various shipping provider APIs such as DHL. I have to deal with the enormous API request (and response) definitions. I am just creating a DTO class for each level of JSON key, which results in a HUGE amount of classes. I have a hunch this problem can be solved better with anonymous classes, but their support is not great yet - PHPStorm has a breaking bug with their autocompletion and I am too dumb to figure out a better solution in any case. However, I totally agree with Levi in that the way forward is better towards `new class() extends $someClass` and not "all anonymous classes final by default". It may open patterns and opportunities we have yet to think about.

Larry Garfield

3 years ago
On Sat, May 6, 2023, at 2:16 AM, Rokas Šleinius wrote:
> On Fri, 5 May 2023 at 23:58, Levi Morrison via internals > <internals@lists.php.net> wrote: >> >> I am not sure about making them final by default. I think it's a more >> consistent language design to allow `new final class()` as you >> originally proposed. Although I don't know why anyone would want to >> extend anonymous classes, we can see that people do, in fact, do it. I >> don't see why we couldn't allow `new class() extends $someClass` in >> the future to specifically allow them to do this. I mean, I'm not >> going to lobby for it, I'm just pointing out that is more aligned and >> consistent with other parts of the language, than to simply make it >> final by default. >> >> Cheers. >> >> -- >> PHP Internals - PHP Runtime Development Mailing List >> To unsubscribe, visit: https://www.php.net/unsub.php >> > > My work currently is integrating with various shipping provider APIs > such as DHL. I have to deal with the enormous API request (and > response) definitions. I am just creating a DTO class for each level > of JSON key, which results in a HUGE amount of classes. > > I have a hunch this problem can be solved better with anonymous > classes, but their support is not great yet - PHPStorm has a breaking > bug with their autocompletion and I am too dumb to figure out a better > solution in any case.
I think you're on the right track with named classes, honestly. With current PHP versions that's syntactically a lot nicer than it used to be.
> However, I totally agree with Levi in that the way forward is better > towards `new class() extends $someClass` and not "all anonymous > classes final by default". It may open patterns and opportunities we > have yet to think about.
My understanding of the engine implementation is that extending from a class dynamically would be really really hard. (Anon classes are not defined at runtime, they get defined at compile time, just with an auto-generated name.) That said, I have to agree here as well that I'm not a fan of forcing anon classes to be final, but if someone could figure out dynamic-extension anon classes, I would be a happy camper. --Larry Garfield