php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #42937 __call() method not invoked when methods are called on parent from child class
Submitted: 2007-10-11 23:08 UTC Modified: 2007-11-12 09:12 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: jmaxwilson at sixteensmallstones dot org Assigned: dmitry
Status: Closed Package: Scripting Engine problem
PHP Version: 5.2.4 OS: Windows XP
Private report: No CVE-ID:
 [2007-10-11 23:08 UTC] jmaxwilson at sixteensmallstones dot org
Description:
------------
If __call() is used to implement a method in a parent class, and the method is overridden in an inherited child class using a real method declaration that calls parent::methodName(), __call() is never invoked and PHP reports a fatal error saying that the method is undefined.

You can work around the bug by replacing parent::methodName() with parent::__call('methodName',null), but it means that you have to know which of the parent's methods are implemented using __call() in order to override them in a child class.

The child class should be agnostic to whether the parent's methods are real or magic.

This bug was reported in PHP5.1 RC1 (http://bugs.php.net/bug.php?id=34739) but was improperly marked as bogus with the explanation that "__call() is not used when calling static methods."  The use of the paamayim-nekudotayim (::) with the parent keyword is not to resolve static scope but to resolve inherited scope for an overridden method, therefore the issue should be reconsidered.

Reproduce code:
---------------
<?php
class A {
	function __call($strMethod, $arrArgs) {
				return "PHP " .phpversion();
	}
}

class B extends A {
	function getVersion() {
		return parent::getVersion() . " Rocks!";
	}
}

$A = new A();
echo $A->getVersion() . "<br/>";

$B = new B();
echo $B->getVersion() . "<br/>";
?>

Expected result:
----------------
PHP 5.2.4
PHP 5.2.4 Rocks!

Actual result:
--------------
PHP 5.2.4

Fatal error: Call to undefined method A::getversion() in C:\www\test.php on line 10

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-10-12 10:11 UTC] judas dot iscariote at gmail dot com
This is fixed in 5_3 but you have to define __callstatic like this


<?php
class A {
    function __call($strMethod, $arrArgs) {
                return "PHP " .phpversion();
    }
    
    static function __callstatic($strMethod, $arrArgs)
    {
         return "PHP " .phpversion();
    }
}

class B extends A {
    function getVersion() {
        return parent::getVersion() . " Rocks!";
    }
}

$A = new A();
echo $A->getVersion() . "<br/>";

$B = new B();
echo $B->getVersion() . "<br/>";
?>
 [2007-10-12 21:46 UTC] jmaxwilson at sixteensmallstones dot org
Thanks for the feedback.  However, adding a magic __callstatic() method doesn't actually fix the problem.  I think there is some misunderstanding about the scope resolution operator (::). While it is often used to access the static methods of a class, when applied to the keyword "parent" it is used to access the _instance_ methods of a the parent class. So, calling parent::getVersion() is calling the _instance_ method of the parent from the child class, not a static method.  Why is this important? What if the method needs to get or set properties of the instance?  It must be an instance method. The $this pseudo-variable is not even available within static methods.

To illustrate,  the example code can be modified like this:

<?php
class A {
	var $arrValues = array();
	
	function __construct() {
		$this->arrValues['PHP'] = "PHP " . phpversion();
	}
	
	function __call($strMethod, $arrArgs) {
		return $this->arrValues['PHP'];
	}
}

class B extends A {
	function getVersion() {
		return parent::getVersion() . " Rocks!";
	}
}

$A = new A();
echo $A->getVersion() . "<br/>";

$B = new B();
echo $B->getVersion() . "<br/>";
?>

It would be incorrect for the engine to call the __callstatic() magic method when a child class calls a parent's method. I hope that is not what 5_3 does.
 [2007-11-10 00:35 UTC] stas@php.net
I think parent:: should use __call, since it's not in fact a static call. 
 [2007-11-12 09:12 UTC] dmitry@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 [2014-03-05 04:10 UTC] bloodynumen at 163 dot com
5.2.9 : Changed __call() to be invoked on private/protected method access, similar to properties and __get(). (Andrei)
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Fri Apr 18 15:02:26 2014 UTC