__callStatic没有被调用?

mom*_*omo 8 php static class

我知道以下可能会在其他地方产生问题并且可能是糟糕的设计,但我仍然想知道为什么会失败(对于我自己的启发):

class Test {
    // singleton
    private function __construct(){}
    private static $i;
    public static function instance(){
        if(!self::$i){
            self::$i = new Test();
        }
        return self::$i;
    }
    // pass static requests to the instance
    public static function __callStatic($method, $parameters){
        return call_user_func_array(array(self::instance(), $method), $parameters);
    }
    private $someVar = 1;
    public function getSomeVar(){
        return $this->someVar;
    }
}

print Test::getSomeVar();
Run Code Online (Sandbox Code Playgroud)

错误是 Using $this when not in object context

显然$ this是静态方法不可用的,但静态方法是通过call_user_func_array将它交给实例方法调用,这应该使$ this成为实例...

/编辑

我知道$ this在静态上下文中不可用.但是,这有效:

print call_user_func_array(array(Test::instance(), 'getSomeVar'), array());

这正是__callStatic重载中发生的事情,所以有些不对劲......

/编辑2

范围肯定是奇怪的处理.如果你将单例实例拉到任何其他类,它按预期工作:

class Test {
    // singleton
    private function __construct(){}
    private static $i;
    public static function instance(){
        if(!self::$i){
            self::$i = new Blah();
        }
        return self::$i;
    }
    // pass static requests to the instance
    public static function __callStatic($method, $parameters){
        return call_user_func_array(array(static::instance(), $method), $parameters);
    }
}

class Blah {
    private $someVar = 1;
    public function getSomeVar(){
        return $this->someVar;
    }
}

print Test::getSomeVar();
Run Code Online (Sandbox Code Playgroud)

hak*_*kre 11

您不能通过PHP中的调用来静态化您的对象方法__callStatic.只有当目前为止的方法不存在时才会调用它.在你的情况下Test::getSomeVar()已经定义.

由于向后兼容性,PHP不检查是否只存在静态方法,但实际上通常存在方法.

在您的情况下,您静态调用非静态方法,因此$this未定义,因为__callStatic尚未调用.如果您已将警告和通知启用到最高级别(建议用于开发),PHP会向您发出警告.

因此,正确的用法是:

echo Test::instance()->getSomeVar();
Run Code Online (Sandbox Code Playgroud)

与Singleton的任何其他实现一样.

所以,你只是用__callStatic错了,它仅适用于方法不是没有定义.为作业选择其他工具/设计,例如您在Blah课堂上使用的聚合示例.

进一步说明:

你通常应该阻止在PHP中使用任何静态上下文,特别是当你在这里利用很多魔术功能时,这是另一种气味.您完成代码之前,您似乎遇到了一堆设计问题.您只会增加难以调试和维护所有这些代码的可能性.但那只是你没有说在某个时候你没有被警告过.

谁需要单身?如果你想了解更多.

  • 如果他们使用静态调用进行装饰,Lavarel是一个创建全局变量的框架.通常是多余的东西,PHP提供开箱即用的全局变量.可能他们并不真的想要这部分代码,所以他们通过*decoration*添加静态调用,这是一种更常见的模式:http://en.wikipedia.org/wiki/Decorator_pattern - 但静态装饰器会破坏灵活性这听起来也不适合框架 - 另见http://i.imgur.com/RJEsz.png (2认同)