Re: Re: Re: Ambiguity in the oop5 visibility docs
| From: | Nikita Popov | 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