On Sat, Aug 2, 2025, at 22:18, Valentin Udaltsov wrote: > On Sat, Aug 2, 2025, at 22:17, Rob Landers <rob@bottled.codes> wrote: >> __ >> On Sat, Aug 2, 2025, at 19:04, Alexandru Pătrănescu wrote: >>> >>> >>> On Sat, Aug 2, 2025, 17:10 Rob Landers <rob@bottled.codes> wrote: >>>> __ >>>> >>>> >>>> On Sat, Aug 2, 2025, at 16:04, Alexandru Pătrănescu wrote: >>>>> >>>>> >>>>> On Sat, Aug 2, 2025 at 12:10 PM Rob Landers <rob@bottled.codes> wrote: >>>>>> __ >>>>>> On Tue, Jul 29, 2025, at 20:11, Jonathan Vollebregt wrote: >>>>>>> I came across this edge case today: >>>>>>> >>>>>>> https://3v4l.org/R3Q8D >>>>>>> >>>>>>> Both psalm and phpstan think this code is A-OK (Once you add the >>>>>>> requisite type hints) but it causes fatal errors way back to PHP 5.0.0 >>>>>>> >>>>>>> ...<snip>... >>>>>> >>>>>> It's not an edge case, in C2, you redefine a protected variable with the >>>>>> same name and shadowed the original $v. That $v is different than C's >>>>>> $v. It's easiest to see this with static access: >>>>>> https://3v4l.org/0SRWb#v8.4.10 >>>>>> >>>>>> However, I don't know of any way to unshadow a property from $this to >>>>>> access the ancestor's value (other than using private access), but it >>>>>> exists and takes up memory; just accessing it is the hard part. >>>>>> >>>>>> — Rob >>>>> >>>>> >>>>> Hi Rob, >>>>> >>>>> I'm pretty sure that there is no shadowing happening in the example. >>>>> When the child instance is created, there is just one slot for the >>>>> property, as the child one replaces the parent one. >>>>> So basically the child property overrides the parent property rather than >>>>> shadowing it. >>>>> >>>>> True shadowing (two slots) only occurs when the parent property is >>>>> declared private. >>>>> >>>>> It's just that when redefining, it stores the declaring class, and so >>>>> there is this sibling class access issue. >>>>> >>>>> I'm wondering now if the access shouldn't be relaxed, in case we have the >>>>> parent class that initially defined the property. >>>>> >>>>> Of course, we should focus on non-static properties, as static ones are >>>>> different things, and there is some shadowing there. >>>>> >>>>> -- >>>>> Alex >>>> >>>> Hi Alex, >>>> >>>> I’m not sure what you mean? https://3v4l.org/WKILh#v8.4.10 >>>> >>>> There is clearly shadowing going on. >>>> >>>> >>> >>> Hi Rob, >>> >>> As I said, let's leave aside the static case, as the question from Jonathan >>> was not about that. >>> >>> Given the class P that defines a protected property with value 1, >>> and a class C that extends P and re-defines the protected property with the >>> value 2, >>> please show me an example where you could get from an instance of class C >>> the value 1 of the parent class property that you think it's shadowed. >>> Bonus point, if you manage that, you could also set it to something else, >>> and so have a hidden storage for any object of class C that is not really >>> visible normally. >>> >>> As far as I know, there is no way to achieve that, and the reason is >>> because at runtime the objects have a single slot for the protected >>> property; the child class property overrides the parent class property when >>> redeclared, and does not shadow it. >>> But please prove me wrong. >>> >>> >>> Thanks, >>> Alex >>> >> >> I mentioned in my first reply, there is no way to get an instance-level >> property unshadowed. It is there though (according to inheritance.c, if I’m >> reading it right, it is still accessible, just not from user-land). >> >> In any case, there are lots of interesting footguns with properties and >> inheritance: Problem with abstract nested object · Issue #47 · Crell/Serde >> <https://github.com/Crell/Serde/issues/47#issuecomment-1890966829>. >> >>> Could it be considered a bug that my first example produces a fatal >>> error instead of trying to access the shadowed parent property that it >>> has access to and is typed to use? >> >> Other languages (such as C#, Java, etc: >> https://www.programiz.com/online-compiler/0ud6UO24mHOTU) don’t allow you to >> access protected properties/methods on sibling classes. This is because >> "protected" is usually used in the context of inheritance; access is usually >> restricted to "myself" or "children" and a sibling is neither of those. If >> there is a bug, the bug is that you can access a sibling’s protected >> properties, at all. >> >> — Rob > > > If there is a bug, the bug is that you can access a sibling’s protected > > properties, at all. > > In 2006 the absence of this feature was fixed as a bug and meged in PHP 5.2: > https://bugs.php.net/bug.php?id=37632 > In 2020 Nikita Popov agreed that this is expected: > https://x.com/nikita_ppv/status/1261633126687805440 > > So one way is to explicitly mention this feature in the Visibility docs > <https://www.php.net/manual/en/language.oop5.visibility.php> and fix the > redeclaration issue to make things consistent. > > The other way is to deprecate sibling relations. > > -- > Valentin
I don’t think the redeclaration is a bug though, as is mentioned in the linked bug report about properties: https://bugs.php.net/bug.php?id=37212, it is pretty clear to me that people expect a redeclaration would be a fatal error, but not accessing a property declared in a shared parent scope (emphasis mine): > The property *is not being redeclared in C*, though. *It is still a property > of A, structure-wise.* A method declared and called in the same way as the > property does not cause any error. This has been the case for years, so I don’t think it is a bug. I was only saying that if there is a bug, the bug would be that you can access another class’s protected properties that aren’t a parent or sibling. I didn’t really go into why, but IMHO, it breaks LSP, since it allows sibling classes to depend on each other’s internals, breaking substitutability (particularly in regards to hooks). — Rob