简体   繁体   English

PHP从__getStatic()返回对象实例

[英]PHP return object instance from __getStatic()

PHP has a magic method __getStatic() that allows overloading of static method calls. PHP有一个神奇的方法__getStatic() ,它允许重载静态方法调用。 I have a class with a fluent interface which performs integrity checks. 我有一个带有流畅接口的类,可以执行完整性检查。 I call it like this:- 我这样称呼它:

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

However, I would like to call it like this:- 但是,我想这样称呼它:

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

I thought that having this magic method in my base class would allow me to do this:- 我以为在我的基类中拥有这个魔术方法将使我能够做到这一点:

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

But new self() produces an instance of the class that the calling code is in, and not the class which __callStatic() exists in, why is this? 但是new self()会生成调用代码所在类的实例,而不是__callStatic()存在的类的__callStatic() ,这是为什么? and how can I get around it? 我该如何解决呢?

I have also tried new static and this does the same thing. 我也尝试过new static ,这也做同样的事情。

I know this must be possible because Laravel's QueryBuilder has an interface like DB::table()->... and this uses method chaining, returning object instances, not static classes. 我知道这是有可能的,因为Laravel的QueryBuilder具有类似DB::table()->...的接口DB::table()->...并且它使用方法链接,返回对象实例,而不是静态类。 I have had a look at the Laravel code, but I think they create the instances somewhere else in the application and they are stored in a class member ready to be returned. 我看过Laravel代码,但是我认为它们在应用程序的其他位置创建了实例,并将它们存储在准备返回的类成员中。

The magic method __callStatic is only called for methods which don't exist , so in this case it will simply not run. 魔术方法__callStatic仅针对不存在的方法调用,因此在这种情况下,它将根本无法运行。

Consider the following simplified example: 考虑下面的简化示例:

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

If you run this ( here's an online demo ) you will see that it is the "real" bar() method that is called. 如果运行此程序( 这是一个在线演示 ),您将看到被调用的是“真实” bar()方法。

There can only be one method named bar on the class, so PHP's only other option would be to complain that bar() should be static - which it does, but non-fatally. 在类上只能有一个名为bar方法,因此PHP的另一种选择是抱怨bar()应该是static -它确实是static ,但不是致命的。


The reason you see an instance of the calling class is not that $instance is instantiated with the wrong class, but because when your method is called non-statically, $this "leaks" from the enclosing scope. 您看到调用类实例的原因不是$instance用错误的类$instance化,而是因为当您的方法被非静态调用时, $this从封闭范围中“泄漏”。

In the following example, $this ends up being the instance of Bar : 在下面的示例中, $this最终成为Bar的实例:

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

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

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

Live Demo 现场演示

As @IMSoP pointed out, __getStatic() is only called if there is no method with the name called - not just if there isn't a static method with the name. 正如@IMSoP所指出的, __getStatic()仅在没有名称被调用的方法时才被调用-不仅是在没有名称静态方法的情况下也是如此。

So the workaround to allow calls such as CheckClass::forActive->sites() is to give all the non static method names a prefix such as '_' and have a magic method __call() which will add the prefix in. 因此,允许诸如CheckClass::forActive->sites()调用的变通办法是为所有非静态方法名称赋予一个前缀,例如'_',并具有一个魔术方法__call()来添加该前缀。

This means if I do CheckClass::forActive() the method forActive() doesn't exist, so __getStatic() will be called and will create an instance of the object and try to call the desired method. 这意味着,如果我做CheckClass::forActive()方法forActive()不存在,所以__getStatic()将被调用,将创建对象的实例,并尝试调用所需的方法。 But the method doesn't exist because we've prefix it, so PHP will call the __call() magic method which will add the prefix and call the prefixed method. 但是该方法不存在,因为我们已经为其添加了前缀,因此PHP将调用__call()魔术方法,该方法将添加前缀并调用带前缀的方法。

So the 2 functions are:- 所以这两个函数是:

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