问题
My situation is best described with a bit of code:
class Foo {
function bar () {
echo "called Foo::bar()";
}
}
class SubFoo extends Foo {
function __call($func) {
if ($func == "bar") {
echo "intercepted bar()!";
}
}
}
$subFoo = new SubFoo();
// what actually happens:
$subFoo->bar(); // "called Foo:bar()"
// what would be nice:
$subFoo->bar(); // "intercepted bar()!"
I know I can get this to work by redefining bar()
(and all the other relevant methods) in the sub-class, but for my purposes, it'd be nice if the __call
function could handle them. It'd just make things a lot neater and more manageable.
Is this possible in PHP?
回答1:
__call() is only invoked when the function isn't otherwise found so your example, as written, is not possible.
回答2:
It can't be done directly, but this is one possible alternative:
class SubFoo { // does not extend
function __construct() {
$this->__foo = new Foo; // sub-object instead
}
function __call($func, $args) {
echo "intercepted $func()!\n";
call_user_func_array(array($this->__foo, $func), $args);
}
}
This sort of thing is good for debugging and testing, but you want to avoid __call()
and friends as much as possible in production code as they are not very efficient.
回答3:
One thing you can try is to set your functions scope to private or protected. When one private function is called from outside the class it calls the __call magic method and you can exploit it.
回答4:
If you need to add something extra to the parent bar(), would this be doable?
class SubFoo extends Foo {
function bar() {
// Do something else first
parent::bar();
}
}
or is this just a question from curiosity?
回答5:
What you could do to have the same effect is the following:
<?php
class hooked{
public $value;
function __construct(){
$this->value = "your function";
}
// Only called when function does not exist.
function __call($name, $arguments){
$reroute = array(
"rerouted" => "hooked_function"
);
// Set the prefix to whatever you like available in function names.
$prefix = "_";
// Remove the prefix and check wether the function exists.
$function_name = substr($name, strlen($prefix));
if(method_exists($this, $function_name)){
// Handle prefix methods.
call_user_func_array(array($this, $function_name), $arguments);
}elseif(array_key_exists($name, $reroute)){
if(method_exists($this, $reroute[$name])){
call_user_func_array(array($this, $reroute[$name]), $arguments);
}else{
throw new Exception("Function <strong>{$reroute[$name]}</strong> does not exist.\n");
}
}else{
throw new Exception("Function <strong>$name</strong> does not exist.\n");
}
}
function hooked_function($one = "", $two = ""){
echo "{$this->value} $one $two";
}
}
$hooked = new hooked();
$hooked->_hooked_function("is", "hooked. ");
// Echo's: "your function is hooked."
$hooked->rerouted("is", "rerouted.");
// Echo's: "our function is rerouted."
?>
来源:https://stackoverflow.com/questions/1535180/phps-magic-method-call-on-subclasses