Моя ситуация лучше всего описывается небольшим количеством кода:
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()!"
Я знаю, что могу заставить это работать, переопределяя bar()
(и все другие соответствующие методы) в подклассе, но для моих целей было бы неплохо, если __call
функция __call
могла их обрабатывать. Это просто сделало бы вещи более аккуратными и более управляемыми.
Возможно ли это в PHP?
__call()
вызывается только тогда, когда функция не встречается иначе, поэтому ваш пример, как написано, невозможен.
Это невозможно сделать напрямую, но это одна из возможных альтернатив:
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); } }
Такая вещь хороша для отладки и тестирования, но вы должны избегать __call()
и друзей как можно больше в производственном коде, поскольку они не очень эффективны.
Одна вещь, которую вы можете попробовать, – это настроить объем ваших функций на частные или защищенные. Когда одна частная функция вызывается извне класса, она вызывает метод __call magic, и вы можете ее использовать.
Если вам нужно добавить что-то лишнее в родительский бар (), можно ли это сделать?
class SubFoo extends Foo { function bar() { // Do something else first parent::bar(); } }
или это просто вопрос из любопытства?
То, что вы можете сделать, чтобы иметь такой же эффект, следующее:
<?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." ?>