簡體   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