首页 > 解决方案 > 从特征覆盖类方法并在特征中再次调用它

问题描述

我正在尝试从使用特征的类中覆盖一个方法(实际上不是一个方法,而是一个不存在的触发 callStatic() 的方法)。但是从特征的方法中,我需要能够从类中调用基方法。(见代码)

namespace Foundation\Traits;

use Foundation\Cache\ModelCache;

trait Cacheable
{
    public static function find($id, $columns = ['*'])
    {
        if ((bool)config('model.caching')) {
            $model = ModelCache::findOrRequery($id, get_called_class());
            return self::filterFromColumns($model, $columns);
        }
        return self::findWithoutCache($id, $columns);
    }

    public static function findWithoutCache($id, $columns = ['*'])
    {
        return parent::find($id, $columns);
    }

    private static function filterFromColumns($model, $columns)
    {
        if ($columns !== ['*']) {
            return collect($model)->first($columns);
        }
        return $model;
    }
}

问题是 find 方法陷入了无限循环,因为它在 trait 上调用 find 方法,而不是在使用 trait 的类上调用。

这也不能解决问题:

    public static function findWithoutCache($id, $columns = ['*'])
    {
        return parent::__callStatic('find', [$id, $columns]);
    }

我该如何解决这个问题?

标签: phpoopobjecttraitssoftware-design

解决方案


我认为您还有其他事情要做,特征绝对可以调用父类上被特征覆盖的方法,就像您可以直接在继承类中一样。这是一个例子:

<?php
trait MyTrait
{
    public static function find()
    {
        echo 'MyTrait::find'.PHP_EOL;
        self::findWithoutCache();
    }

    public static function findWithoutCache()
    {
        echo 'MyTrait::findWithoutCache'.PHP_EOL;

        parent::find();
    }
}

class MyBaseClass
{
    public static function find()
    {
        echo 'MyBaseClass::find'.PHP_EOL;
    }
}

class MyClass extends MyBaseClass
{
    use MyTrait;
}

$myClass = new MyClass();
$myClass::find();

编辑:

根据您对 Laravel 模型中发生的这种情况的评论,您不能find静态调用该方法,您必须拥有模型的实例。如果您查看类中的__call__callStatic方法中 的代码Illuminate\Database\Eloquent\Model,就会清楚发生了什么:

 /**
 * Handle dynamic method calls into the model.
 *
 * @param  string  $method
 * @param  array  $parameters
 * @return mixed
 */
public function __call($method, $parameters)
{
    if (in_array($method, ['increment', 'decrement'])) {
        return call_user_func_array([$this, $method], $parameters);
    }

    $query = $this->newQuery();

    return call_user_func_array([$query, $method], $parameters);
}

/**
 * Handle dynamic static method calls into the method.
 *
 * @param  string  $method
 * @param  array  $parameters
 * @return mixed
 */
public static function __callStatic($method, $parameters)
{
    $instance = new static;

    return call_user_func_array([$instance, $method], $parameters);
}

在父对象上静态调用find只是调用特征中的方法,但是如果你调用find模型的实例,aIlluminate\Database\Eloquent将被实例化,它的find方法将被调用,并返回结果。

最重要的是,Eloquent 似乎并没有按照您想要的方式静态工作。


推荐阅读