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

Reply via email to