使静态变为非静态(Magic Method)

时间:2018-04-16 20:21:42

标签: php laravel

你好基本上在Laravel你可以做这样的事情

User::get();

而且我知道场景背后的laravel通过调用一个名为__callStatic()的魔术方法并从中返回new static来实现这一点。

__callStatic仅适用于无法访问或不存在的方法。

所以我的问题是,当User::get()实际上是get()时,你如何才能做到public function

修改
鉴于我在这里有这个简单的代码

class First
{
    public function callThis()
    {
        return 'Yo';
    }

    public static function __callStatic($name, $arguments)
    {
        dd('This is not working');
    }
}

First::callThis();

我明白了 Non-static method First::callThis() should not be called statically

1 个答案:

答案 0 :(得分:2)

它无法正常工作,因为您无法静态调用非静态方法。 它与get()等方法一起使用的原因是因为这些调用被委托给查询实例 - 它们实际上并不存在于模型本身上。

如果你检查__call方法,它应该变得更加清晰:

public function __call($method, $parameters)
{
    if (in_array($method, ['increment', 'decrement'])) {
        return $this->$method(...$parameters);
    }

    return $this->newQuery()->$method(...$parameters);
}

所以即使默认的__callStatic方法实现调用非静态方法:

public static function __callStatic($method, $parameters)
{
    return (new static)->$method(...$parameters);
}

您的代码会立即失败,因为您的模型实际上会包含具有相同名称的public非静态方法。

您会看到__call方法检查方法的名称是否在incrementdecrement的数组中 - 如果是 - 它会调用它们。

protected function increment($column, $amount = 1, array $extra = [])
{
    return $this->incrementOrDecrement($column, $amount, $extra, 'increment');
}

protected function decrement($column, $amount = 1, array $extra = [])
{
    return $this->incrementOrDecrement($column, $amount, $extra, 'decrement');
}

这两种方法在模型实例上实际上都是非静态的,但它们的可见性设置为protected,因此无论如何你都无法在模型的实例上调用它们 - 访问它们的唯一方法是使用魔术方法 - 在这种情况下,静态调用可以正常工作。

换句话说,如果您将方法的可见性更改为protected并覆盖__call方法以在阵列中包含您的方法名称,那么您的代码应该可以使用

protected function callThis()
{
    return 'Yo';
}

public function __call($method, $parameters)
{
    if (in_array($method, ['increment', 'decrement', 'callThis'])) {
        return $this->$method(...$parameters);
    }

    return $this->newQuery()->$method(...$parameters);
}

希望这有帮助。