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

From: Date: Thu, 28 Mar 2019 10:20:08 +0000
Subject: Re: Re: Re: Ambiguity in the oop5 visibility docs
References: 1 2 3 4 5  Groups: php.doc 
Request: Send a blank email to phpdoc+get-969387198@lists.php.net to get a copy of this message
On Thu, Mar 28, 2019 at 11:14 AM Christoph M. Becker <cmbecker69@gmx.de> wrote: > On 28.03.2019 at 10:32, Nikita Popov wrote: > > > 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. > > Changing the actual behavior should better be discussed on internals@, > though. :) > > -- > Christoph M. Becker > Gah, part of this thread was cross-posted to internals, but the specific mail I replied to wasn't. I'll create an RFC for this, not much point discussing without a proposal. Nikita

« previous php.doc (#969387198) next »