PHP 子类的神奇方法 __call

发布于 2024-08-07 13:24:05 字数 568 浏览 5 评论 0原文

我的情况最好用一些代码来描述:

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 中可能吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

寄意 2024-08-14 13:24:05

__call()仅当未找到该函数时才被调用,因此您的示例(如所写)是不可能的。

__call() is only invoked when the function isn't otherwise found so your example, as written, is not possible.

迷爱 2024-08-14 13:24:05

您可以尝试的一件事是将函数范围设置为私有或受保护。当从类外部调用一个私有函数时,它会调用 __call 魔术方法,您可以利用它。

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.

忘你却要生生世世 2024-08-14 13:24:05

它不能直接完成,但这是一种可能的替代方案:

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() 和朋友因为他们的效率不是很高。

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.

孤城病女 2024-08-14 13:24:05

如果您需要向父 bar() 添加额外的内容,这可行吗?

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

或者这只是出于好奇而提出的问题?

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?

二智少女猫性小仙女 2024-08-14 13:24:05

为了达到相同的效果,您可以执行以下操作:

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

?>

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

?>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文