从特征中的覆盖魔法方法调用父魔法方法

Call parent magic method from override magic method in a trait

问题

我正在开源一个包含魔术方法 __call() 的特性。在测试过程中,当使用特征的 class 的父 class 包含 __call 方法时,我遇到了挑战。

我试过的

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

这会导致致命错误:无法访问父级::当前class范围没有父级

我还尝试了以下,基于其他answers:

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

这会导致 分段错误:11。我想是因为无限调用循环。

问题

如何从特征的 __call 方法中调用父的 __call 方法?

如果不能直接从 trait 内部调用,否则我如何调用父级的 __call 方法?

请检查以下代码:

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

编辑:我认为这将涵盖所有可能性。

这里的问题是,如果您在没有父项的 class 中使用此特征,则此调用将失败。您可以考虑在调用父函数之前检查 class 是否有父函数。这可能看起来像这样:

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

我还要说这可能不是最好的设计方法。我不认为像 trait 这样的东西,它应该提供一组可移植的、可组合的功能,应该是采用 class' 继承链中的 changing/overriding 功能。