Re: Re: Re: Ambiguity in the oop5 visibility docs

From: Date: Thu, 28 Mar 2019 09:32:32 +0000
Subject: Re: Re: Re: Ambiguity in the oop5 visibility docs
References: 1 2 3  Groups: php.doc 
Request: Send a blank email to phpdoc+get-969387196@lists.php.net to get a copy of this message
On Tue, May 29, 2018 at 1:41 PM Rowan Collins <rowan.collins@gmail.com> wrote: > On 27 May 2018 at 19:02, Andrew Gromov <andrewgrom@rambler.ru> wrote: > >> class A { >> public function foo(){ >> echo $this->b; // No property $b in parent class >> } >> } >> >> class B extends A { >> protected $b = 'foo'; >> } >> >> $a = new B(); >> $a->foo(); // prints 'foo' >> >> In classic OOP, parent class can't access unknown to him member of child >> class. >> > > > In PHP, classes don't really "know" anything about their structure - > everything is looked up dynamically at run-time. At run-time, there is a > property called "b" on the instance, and it is visible in the current > scope, so the access is allowed. > > You mention "classic OOP", but I'm not aware of any formal definition we > could reference here, only precedent from other languages. Most languages > don't need to worry about this case, because the reference to $this->b > would fail to compile unless b was declared; but PHP can't raise that > error, because accessing a completely undeclared property is allowed. > > > > >> And phrases like >> >> > can be accessed within the class itself and parent classes. >> >> explode the brain! How it can be - reverse inheritance, from child to parent!? >> >> > I discussed a common use case for this in my first response on this > thread: > https://marc.info/?l=phpdoc&m=152727049709620&w=2 > > There is no *inheritance* from child to parent, just access from code > written in a parent class to polymorphic behaviour in the child class. > Want to bump this discussion again, because I still think that the current behavior is incorrect. I think there are two different cases that got conflated here: // This should work. class A { protected function foo() {} } class B extends A { protected function test() { $this->foo(); } } class C extends B { protected function foo() {} } (new C)->test(); This code should of course work. It should work because we have an A::foo() method (the "prototype"), which happens to be overridden by C::foo(), but that's not actually relevant. The inheritance check here is whether B has access to the prototype A::foo(), which is has. If you consider that inheritance is checked against the prototype, then there is actual "reverse visibility" going on here. The other case, and the case that I believe should not work, is the following: // This shouldn't work, but does. class A { protected function test() { $this->foo(); } } class B extends A { protected function foo() {} } (new B)->test(); Here B::foo() does not have a prototype higher up in the hierarchy. We're calling B::foo() from A, which should by any reasonable interpretation not be possible. To allow this call, it should be necessary to also add a protected function foo() to class A, possibly as an abstract method: // This should work. abstract class A { protected abstract function foo(); protected function test() { $this->foo(); } } class B extends A { protected function foo() {} } (new B)->test(); Here once again B::foo() overrides the prototype A::foo(), and A::foo() is of course visible from A. I believe that the current behavior is a leftover from before the introduction of the prototype mechanism in PHP 5.2. Previously just checking visibility in both directions was a poor mans approximation of the correct behavior. However, it both disallowed some legal cases (involving non-linear hierarchies) and allowed illegal cases (accessing protect method from a child). Since PHP 5.2 all the legal cases should be covered by the prototype mechanism and the bidirectional visibility check is just a legacy leftover. We should consider removing it for PHP 8. Nikita

« previous php.doc (#969387196) next »