__callStatic 函数不会被调用,如果存在一个非静态函数。

6

我的代码如下:

<?php

class A {

    public function CallA()
    {
        echo "callA" . PHP_EOL;
    }

    public static function CallB()
    {
        echo "callB" . PHP_EOL;
    }

    public static function __callStatic($method, $args)
    {
        echo "callStatic {$method}";
    }
}

A::CallA();

但是它将会输出:
Strict Standards: Non-static method A::CallA() should not be called statically in /vagrant/hades_install/public/test.php on line 21
callA

也就是说,CallA 方法不会进入 __callStatic 函数。
如果想要通过使用 A::CallA() 调用 __callStatic,应该怎么做呢?

如果您可以将CallA的公共访问权限更改为受保护或私有,则会按预期看到__callStatic()CallA之前触发,但这意味着无法在没有__callStatic()的情况下调用CallA... 这是个难题! - scrowler
在 PHP 中,方法中的 static 关键字仅仅是建议性的,它并不会对调用行为产生很大的影响。 - deceze
2个回答

7
正如文档所解释的那样:

__callStatic()在静态上下文中调用不可访问的方法时触发。

你代码中的 CallA() 方法是可访问的,这就是为什么 PHP 不使用 __callStatic() 并直接调用 CallA() 的唯一选择。
你可以通过使 CallA() 不可访问(重命名或将其可见性更改为 protectedprivate)或直接调用它(丑陋的解决方法)来强制调用 __callStatic()
A::__callStatic('CallA', array());

如果您选择将CallA()设为protected,您需要实现__call()方法才能再次调用CallA()

class A {

    protected function CallA()
    {
        echo "callA" . PHP_EOL;
    }

    public static function CallB()
    {
        echo "callB" . PHP_EOL;
    }

    public static function __callStatic($method, $args)
    {
        echo "callStatic {$method}" . PHP_EOL;
    }

    public function __call($method, $args)
    {
        if ($method == 'CallA') {
            $this->CallA();
        }
    }
}

A::CallA();
A::__callStatic('CallA', array());

$x = new A();
$x->CallA();

它的输出结果为:
callStatic CallA
callStatic CallA
callA

3

另一种方法是保留非静态方法不变,并在静态调用时使用前缀,在__callStatic内解析方法名称。

class A {

    public function CallA()
    {
        echo "callA" . PHP_EOL;
    }

    public static function __callStatic($method, $args)
    {
        $method_name = ltrim($method, '_');
        echo "callStatic {$method_name}" . PHP_EOL;

        $instance = new A();
        return instance->$method_name(...$args); //this only works in PHP 5.6+, for earlier versions use call_user_func_array
    }

}

A::_CallA();

这将输出:
callStatic callA
callA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接