简体   繁体   中英

Override Class method from trait & call it again in the trait

I'm trying to override a method (that is actually not a method but a not existing method that triggers callStatic()) from a class using a trait. But from within the method from the trait i need to be able to call the base method from the class. (see code)

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;
    }
}

The problem is that the find method is stuck in an infinite loop because it calls the find method on the trait instead of the class using the trait.

This does also not fix the problem:

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

How do i get around this problem?

I think you have something else going on, traits can definitely call methods on a parent class that are overridden by the trait, just like you can directly in the inheriting class. Here's an example:

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

Edit:

Based upon your comment about this happening in a Laravel model, you cannot call the find method statically, you have to have an instance of your model. If you look at the code in the __call and __callStatic methods in the Illuminate\\Database\\Eloquent\\Model class, it becomes clear what is going on:

 /**
 * 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);
}

Calling find statically on the parent just calls the method in your trait, but if you call find on an instance of your model, a Illuminate\\Database\\Eloquent will be instantiated, it's find method will be called, and the results will be returned.

Bottom line, Eloquent just doesn't seem to be built to work statically the way you want it to.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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