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 (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 5.2.4 OS: Windows XP
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: jmaxwilson at sixteensmallstones dot org
New email:
PHP Version: OS:

 

 [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

Pull Requests

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-2024 The PHP Group
All rights reserved.
Last updated: Fri Dec 13 13:01:27 2024 UTC