繁体   English   中英

PHP从__getStatic()返回对象实例

[英]PHP return object instance from __getStatic()

PHP有一个神奇的方法__getStatic() ,它允许重载静态方法调用。 我有一个带有流畅接口的类,可以执行完整性检查。 我这样称呼它:

$check = new CheckSomeCondition();
$check->forActive()->sites(array(1,2,3))->check();

但是,我想这样称呼它:

CheckSomeCondition::forActive()->sites(array(1,2,3))->check();

我以为在我的基类中拥有这个魔术方法将使我能够做到这一点:

public static function __callStatic($method, $args)
{
    $instance = new self();
    return call_user_func_array(array($instance, $method), $args);
}

但是new self()会生成调用代码所在类的实例,而不是__callStatic()存在的类的__callStatic() ,这是为什么? 我该如何解决呢?

我也尝试过new static ,这也做同样的事情。

我知道这是有可能的,因为Laravel的QueryBuilder具有类似DB::table()->...的接口DB::table()->...并且它使用方法链接,返回对象实例,而不是静态类。 我看过Laravel代码,但是我认为它们在应用程序的其他位置创建了实例,并将它们存储在准备返回的类成员中。

魔术方法__callStatic仅针对不存在的方法调用,因此在这种情况下,它将根本无法运行。

考虑下面的简化示例:

class Foo
{
    public function bar()
    {
        echo "Running instance method bar()";
    }

    public static function __callStatic($method, $args)
    {
        echo "__callStatic called for non-existent method $method";
    }
}

Foo::bar();

如果运行此程序( 这是一个在线演示 ),您将看到被调用的是“真实” bar()方法。

在类上只能有一个名为bar方法,因此PHP的另一种选择是抱怨bar()应该是static -它确实是static ,但不是致命的。


您看到调用类实例的原因不是$instance用错误的类$instance化,而是因为当您的方法被非静态调用时, $this从封闭范围中“泄漏”。

在下面的示例中, $this最终成为Bar的实例:

class Foo
{
    public function doSomething()
    {
        echo get_class($this);
    }
}

class Bar
{
    public function doSomethingElse()
    {
        Foo::doSomething();
    }
}

$bar = new Bar();
$bar->doSomethingElse();

现场演示

正如@IMSoP所指出的, __getStatic()仅在没有名称被调用的方法时才被调用-不仅是在没有名称静态方法的情况下也是如此。

因此,允许诸如CheckClass::forActive->sites()调用的变通办法是为所有非静态方法名称赋予一个前缀,例如'_',并具有一个魔术方法__call()来添加该前缀。

这意味着,如果我做CheckClass::forActive()方法forActive()不存在,所以__getStatic()将被调用,将创建对象的实例,并尝试调用所需的方法。 但是该方法不存在,因为我们已经为其添加了前缀,因此PHP将调用__call()魔术方法,该方法将添加前缀并调用带前缀的方法。

所以这两个函数是:

public static function __callStatic($method, $args)
{
    $instance = new self;
    return call_user_func_array(array($instance, $method), $args);
}

public static function __call($method, $args)
{
    $method = 'prefix_' . $method;
    return call_user_func_array(array($instance, $method), $args);
}

// Then all our method names need to be prefixed, like so:-
public static function prefix_SomeMethod($method, $args)
{
    // Do something
    return $this;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM