On Sun, Aug 3, 2025, at 11:10, Rowan Tommins [IMSoP] wrote: > On 2 August 2025 21:59:20 BST, Rob Landers <rob@bottled.codes> wrote: > >If this were the case, then creating a base class with default values > >wouldn’t be possible. The memory exists and is set aside for that. > > Sure it would: the default value is just an assignment that happens at a > particular point of the object's lifecycle. For a child class which overrides > the default of a parent (on a public or protected property), only the child > class's assignment will ever be visible. So it would be perfectly valid for > the class entry for the child class to only store that one assignment. I > don't know if that actually happens; maybe the cost of de-duplicating is not > seen as worthwhile, and the assignments are just run in sequence every time. > > Regardless, the philosophical question in this thread seems to be whether > re-declaring a protected property should change the "ownership" of that > property. I think it's natural that a protected property *only* declared in a > sibling class can't be accessed, so some ownership needs to be tracked. > > What seems surprising is that the ownership changes if the same property is > re-declared, especially since the new declaration has to match the original > (e.g. you can't change the type), and every possible access tells the user > the two declarations have been completely merged. > > Intuitively, an identical declaration with no change other than a default > value looks like it would be the same as overwriting the default in a > constructor, but that is not the case. (https://3v4l.org/5iIak vs > https://3v4l.org/rL8pX) > > I'm inclined to agree that this is a bug, regardless of whether it's > difficult to fix in the implementation. > > > Rowan Tommins > [IMSoP] >
I'm not sure that this is a bug. You can redeclare the same type and add hooks (or change them), which breaks all assumptions about substitutability. class A { protected int $v = 2; } class B extends A { public function getValue(A $v): void { echo $v->v; } } class C extends A { protected int $v { set => $this->v * 2; } } $b = new B; $c = new C; $b->getValue($b); $b->getValue($c); C changes all assumptions from B's point of view (technically C is a violation of LSP from the perspective of A, thus it should not pretend to be substitutable as A from the perspective of B when used in this way -- though other properties/methods may in fact be substitutable and be useful). — Rob