问题
I'd like to hide parent methods in some manner so that a child class's __call magic method is invoked for methods defined on the parent. For example:
class C {
function foo() { echo "foo\n"; }
}
class D extends C {
function __call( $method, $args ) { echo "called $name\n"; }
}
$d = new D();
$d->foo();
// desired result: called foo
// actual result: foo
I've checked into rename_function and override_function but those don't work for methods. ReflectionMethod has a setAccessible method I tried, but that seems to only work if you use the ReflectionMethod instance to invoke the method.
Background: attempting to have an RPC Proxy class that can take advantage of PHP's type checking. So, if I have an RPCFoo I can use type hinting or instanceof to enforce type in such a way that I can check that ($RPCFoo instance Foo).
Edit: the base class should be able to be used as is, without the proxy. This is so that proxying can be part of the system configuration, not the code. Think multiple servers all with the same code base, but the ability to assign certain tasks to each. If the local server does not handle the service requested, the class loader would return a proxy instead of the base class. If the local server does handle the service requested, it would return the base class.
Edit Again: the methods presented are workable, but hide the designed interface of the base class from IDEs and reflection. I was attempting to make the proxy implementation clean so that one simply had to inherit from the base class and implement a proxy interface. In order to maintain the base class interface, the proxy developer would have to re-implement all the public and protected methods to make a remote call. Then when something is updated in the base class, the proxy would have to be updated as well. In the end, I think I'm simply going to go the route of writing a proxy generator that uses reflection do this for the developer.
Thanks for the replies!
回答1:
You have to set access to foo
method to private
:
class C {
private function foo() {
echo "foo\n";
}
public function __call($method, $args) {
if(is_callable(array($this,$method))) {
return call_user_func_array(array($this,$method), $args);
} else {
trigger_error("Call to undefined method '{$method}'");
}
}
}
回答2:
class C {
public function __call($method, $args) {
return call_user_func_array(array(__CLASS__ ,$method), $args);
}
protected function foo() { echo "foo<br />"; }
}
class D extends C {
function __call( $method, $args ) { echo "called $method<br/>"; }
}
$d = new D();
$d->foo();
$c = new C();
$c->foo();
回答3:
I know this question is a bit old, but I got it working so I post it here to help people facing the same problem.
My solution to override parent methods with the magic __call() method:
public function foo($p1, $p2, $p3)
{
if (get_class($this) == __CLASS__) {
/* Do stuff here */
} elseif (method_exists($this, '__call')) {
return call_user_func_array([$this, '__call'], ['foo', func_get_args()]);
}
return false;
}
The only limitation is that the parent class itself cannot have a magic __call() method, otherwise it would call the __call() method from the parent class instead of an extended child class.
来源:https://stackoverflow.com/questions/9151722/php-overriding-parent-methods-with-call