Подтвердить что ты не робот

Вызов метода родительской магии из метода переопределения магии в признаке

Проблема

Я открываю источник, который включает магический метод __call(). Во время тестирования я столкнулся с проблемой, когда родительский класс класса с использованием признака содержит метод __call.

Что я пробовал

trait SomeTrait {
    public function __call($method, array $parameters) {
        // ...
        return parent::__call($method, $parameters);
    }
}

Это приводит к фатальной ошибке: Невозможно получить доступ к родительскому:: если текущий класс не имеет родительского

Я также пробовал следующее, основанное на некоторых других ответах:

return call_user_func_array([$this, '__call'], [$method, $parameters]);

Это приводит к ошибке Сегментации: 11. Я предполагаю, что из-за бесконечного цикла вызова.

Вопрос

Как я могу вызвать родительский метод __call из метода __call признака?

Если это невозможно изнутри признака напрямую, как я могу вызвать родительский метод __call в противном случае?

4b9b3361

Ответ 1

Пожалуйста, проверьте код ниже:

trait SomeTrait
{
    public function __call($method, array $parameters)
    {
        // ...
        return is_callable(['parent', '__call']) ? parent::__call($method, $parameters) : null;
    }
}

class GreatParentClass
{
    public function __call($method, array $parameters)
    {
        return 'bar';
    }
}

class ParenClassWithoutCall
{

}

class ProxyClass extends GreatParentClass
{

}

class FooClass extends ProxyClass
{
    use SomeTrait;
}

class BarClass extends GreatParentClass
{
    use SomeTrait;
}

class BazClass extends ParenClassWithoutCall
{
    use SomeTrait;
}

class SomeClassWithoutParent
{
    use SomeTrait;
}

$class = new FooClass();
var_dump($class->foobar());

$class = new BarClass();
var_dump($class->foobar());

$class = new BazClass();
var_dump($class->foobar());

$class = new SomeClassWithoutParent();
var_dump($class->foobar());

Это напечатает:

string(3) "bar"
string(3) "bar"
NULL
NULL

Песочница с кодом для проверки: http://3v4l.org/R8hI3

EDIT: Я думаю, что это будет охватывать все возможности.

Ответ 2

Хорошо, проблема в том, что если вы используете этот признак в классе без родителя, этот вызов завершится неудачно. Вы можете рассмотреть возможность проверки, имеет ли класс родительский объект перед вызовом родительской функции. Это может выглядеть так:

trait SomeTrait {
    public function __call($method, array $parameters) {
        // ...
        if (count(class_parents($this)) {
            return parent::__call($method, $parameters);
        }
    }
}

Я бы также сказал, что это не лучший подход к дизайну. Я не думаю, что что-то вроде черты, которая должна представить переносимый, составной набор функций, должна меняться/переопределять функциональные возможности в цепочке наследования принятого класса.