Re: Re: Re: Ambiguity in the oop5 visibility docs
| From: | Christoph M. Becker | Date: | Thu, 28 Mar 2019 10:14:47 +0000 |
| Subject: | Re: Re: Re: Ambiguity in the oop5 visibility docs | ||
| References: | 1 2 3 4 | Groups: | php.doc |
| Request: | Send a blank email to phpdoc+get-969387197@lists.php.net to get a copy of this message | ||
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