8

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

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();

错误是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();
4

2 回答 2

11

您不能通过PHP 中的调用来静态化您的对象方法__callStatic。它只会在该方法目前不存在时被调用(包括在调用上下文中不可见)。在您的情况下Test::getSomeVar()已经定义。

由于向后兼容,PHP 不检查是否只存在静态方法,而是检查是否存在方法。

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

因此正确的用法是:

echo Test::instance()->getSomeVar();

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

所以你只是用__callStatic错了,它只适用于尚未定义的方法。为作业选择另一个工具/设计,例如您在Blah课堂上使用的聚合示例。

进一步说明:

无论如何,您通常应该避免在 PHP 中使用任何静态上下文,尤其是当您在这里也利用了许多神奇的功能时,这是另一种味道。看起来您甚至在完成代码之前就遇到了一堆设计问题。所有这些只会增加您遇到难以调试和维护代码的可能性。但这只是为了让你不要说在一段时间内你没有被警告过。

请参阅谁需要单例?如果您想了解更多信息。

于 2012-11-19T14:49:10.377 回答
1

它不是那样工作的。在static通话中,您没有实例,没有对象,也没有$this. 调用 static 仅适用于$this不可用的静态方法。

文档说:

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

我知道这不是您希望的答案。正如您所预料的那样:您不需要在 PHP 中重载,只需创建您的应用程序并将其排除在外。

于 2012-11-19T04:13:01.570 回答