Php __callStatic不被调用吗?

Php __callStatic不被调用吗?,php,class,static,Php,Class,Static,我知道以下内容可能会在其他地方产生问题,可能是糟糕的设计,但我仍然想知道为什么会失败(供我自己启发): 当不在对象上下文中时,错误是使用$this 显然$this在静态方法中不可用,但是静态方法通过call_user_func_数组将其传递给实例方法调用,这应该使$this成为实例 /编辑 我知道$this在静态上下文中不可用。然而,这是可行的: print call\u user\u func\u数组(数组(Test::instance(),'getSomeVar'),数组()) 这正是调用静

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

当不在对象上下文中时,错误是
使用$this

显然$this在静态方法中不可用,但是静态方法通过call_user_func_数组将其传递给实例方法调用,这应该使$this成为实例

/编辑

我知道$this在静态上下文中不可用。然而,这是可行的:

print call\u user\u func\u数组(数组(Test::instance(),'getSomeVar'),数组())

这正是调用静态重载中发生的事情,所以出现了一些问题

/编辑2

范围肯定是得到处理奇怪。如果将singleton实例拉入任何其他类,它将按预期工作:

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

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

文件说:

__调用静态上下文中不可访问的方法时会触发callStatic()

我知道这不是你所希望的答案。正如您所预料的那样:您不需要在PHP中重载,只需创建应用程序并忽略这一点。

您无法通过在PHP中调用静态化对象方法。仅当方法目前不存在时(包括在调用上下文中不可见)才会调用它。在您的案例中,已经定义了
Test::getSomeVar()

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

在本例中,您是静态调用非静态方法,因此未定义
$this
,因为尚未调用
\u callStatic
。如果您启用了最高级别的警告和通知(推荐用于开发),PHP会警告您这一点

因此,正确的用法是:

echo Test::instance()->getSomeVar();
与任何其他单例实现一样

因此,您只是使用了
\uu callStatic
错误,它只适用于尚未定义的方法。为作业选择另一个工具/设计,如您在
Blah
类中使用的聚合示例

另一项说明:

通常情况下,您应该防止在PHP中使用任何静态上下文,尤其是当您在这里利用了许多神奇的功能时,这是另一种味道。看起来在您完成代码之前,您就已经遇到了一堆设计问题。这样做只会增加遇到难以调试和维护的代码的可能性。但这只是为了让你不要说在某个时候你没有被警告过


如果您想了解更多信息,请参阅。

@hakre感谢您的详细回复-为清楚起见,我接受。这不是我个人的工作,而是对一些新的流行框架和微框架的调查结果。例如,laravel,一个备受推崇(但最近才进入PHP框架领域)的人,使用了我上一次编辑中描述的模式(Blah类,他们称之为“负载”)。您的帖子解释了它们为什么分离静态实例。感谢如果他们使用静态调用进行装饰,Lavarel是一个创建全局变量的框架。PHP提供了开箱即用的全局变量,这通常是多余的。可能他们并不真的希望在部分代码中使用这种方式,所以他们通过装饰(一种更常见的模式)添加静态调用:-但是静态装饰器会破坏灵活性,这听起来也不适合框架-另请参见@hakre interest。他们称之为“facade”模式,但我确实深入研究了内部结构,他们使用的方法与我在“Blah”示例中描述的方法相同。根据,看起来下一个版本(4)将实现您描述的decorator模式,仍然使用静态成员通过公共应用程序变量访问单个入口点。-facade模式最多只有一种方法。您的示例中提供的静态方法访问器降低了从对象获益的灵活性,因此是单向的,我不会在其中使用太多的公共模式名称,因为在基于类的编程和全局(静态)变量中,所有这些都会走向错误的方向。当心,在与其他开发人员讨论时,您可能会对这些术语产生混淆。@hakre,好消息。我正在阅读有关国际奥委会和国际直接投资的文章,我想我明白了这一点。问题是对“在静态环境中”的含义的误解。“上下文”是它的“位置”。如果您正在从小部件对象中调用
Widget::foo()
。它在对象上下文中被调用。“::”并不意味着引用PHP手册中的“静态调用”:
\uu callStatic()在静态上下文中调用不可访问的方法时被触发。
-您的方法是公共的,将其设置为私有/受保护的,并且它将按预期工作;)ref:(当然,目标静态方法也应该定义为静态的)
echo Test::instance()->getSomeVar();