Волшебный метод PHP __call на подклассах - PullRequest
9 голосов
/ 08 октября 2009

Моя ситуация лучше всего описана с небольшим количеством кода:

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 могла их обработать. Это просто сделало бы вещи много аккуратнее и более управляемыми.

Возможно ли это в PHP?

Ответы [ 5 ]

14 голосов
/ 08 октября 2009

__call() вызывается только в том случае, если функция не найдена иначе, поэтому ваш пример, как написано, невозможен.

2 голосов
/ 08 октября 2009

Это нельзя сделать напрямую, но это одна из возможных альтернатив:

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() и друзей в производственном коде, поскольку они не очень эффективны.

1 голос
/ 05 апреля 2016

Одна вещь, которую вы можете попробовать, это установить область ваших функций на частную или защищенную. Когда одна частная функция вызывается извне класса, она вызывает магический метод __call, и вы можете использовать ее.

0 голосов
/ 27 декабря 2009

То, что вы могли бы сделать, чтобы получить тот же эффект, следующее:

    <?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."

?>
0 голосов
/ 08 октября 2009

Если вам нужно добавить что-то дополнительное в родительскую панель (), это будет выполнимо?

class SubFoo extends Foo {
    function bar() {
        // Do something else first
        parent::bar();
    }
}

или это просто вопрос из любопытства?

...