php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65828 parent::X() triggers child's __call('X'), instead of parent's __call('X')
Submitted: 2013-10-03 16:02 UTC Modified: 2013-10-04 16:15 UTC
From: stefaan at netlog dot com Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: 5.4.20 OS: OSX, Ubuntu
Private report: No CVE-ID: None
 [2013-10-03 16:02 UTC] stefaan at netlog dot com
Description:
------------
In the code example below the parent::getX() call in BB::getX() resolves to CCC:__call('X') instead of to A:__call('X'), which I would expect.
It seems weird that "parent" in BB:getX() resolves to CCC, which is not the parent of BB (it's vice versa) nor CCC.


I get this behavior on PHP 5.3.26, but also PHP 5.4.20

Test script:
---------------
class A {
    public function whoami() { return 'A'; }
    public function __call($method, array $args) {
        return 'A::__call::' . $method;
    }
}
class BB extends A
{
    public function whoami() { return 'BB'; }
    public function getX() {
        return 'BB::getX (FYI: parent is ' . parent::whoami(). ') -> ' . parent::getX() ;
    }
}
class CCC extends BB {
    public function whoami() { return 'CCC'; }
    public function __call($method, array $args) {
        return 'CCC::__call::' . $method . ' -> ' . parent::__call($method, $args);
    }
}
$c = new CCC();
echo $c->getX() . "\n";


Expected result:
----------------
BB::getX (FYI: parent is A) -> A::__call::getX

Actual result:
--------------
BB::getX (FYI: parent is A) -> CCC::__call::getX -> A::__call::getX

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-10-03 17:46 UTC] rasmus@php.net
-Status: Open +Status: Not a bug
 [2013-10-03 17:46 UTC] rasmus@php.net
That's how classes are composed. There is no bug here. CCC:__call() is the active __call() method  for this instance no matter where in the hierarchy you are. You can explicitly call other versions of methods via lsb, of course. See http://php.net/lsb
 [2013-10-04 16:15 UTC] stefaan at netlog dot com
Thanks for the quick response.

So to get this straight, if I understood you correctly:
in BB::getX():
the call parent::getX() resolves to something like
"method A::getX() called on a CCC instance"
which does not exists and triggers
__call('getX') on the CCC instance, so CCC::__call('getX')


I'm not sure I understood your comment on LSB.
From the test script I learn that "parent::" is "non-LSB" like "self::", but there does not exist a LSB equivalent of "parent::", right? So there is no other option here. (And if there would be, it would result in an endless loop in this case.)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 26 21:01:29 2024 UTC