调用 PHP 方法,同时忽略参数的类型提示


Call a PHP method while ignoring type-hinting on parameters

给定:

class Foo {
    private $bar;
    public function setBar(Bar $bar) {
         $this->bar = $bar;
    }
}

没有办法使用不是Bar实例的参数调用setBar()

$proxy = new Proxy();
$foo = new Foo();
$foo->setBar($proxy);
// with
class Proxy  {
}

这个想法是注入一个代理对象而不是一个Bar实例。Proxy类是泛型的(在依赖注入框架中),不能用于实现/扩展Bar


Reflection API似乎没有提供任何使这成为可能的东西。我希望在不使用 PHP 扩展(标准 PHP 安装> 5.3)的情况下做到这一点(如果可能的话,我试图让eval独自一人)。

注意:是的,这是奇怪的东西,我期待对此的评论,但请留下"答案"以获取问题的实际答案。这不是生产代码。

需要调用 setBar(),还是只需设置私有$bar属性即可解决?

后者可以通过ReflectionProperty::setAccess实现,然后您可以将任何内容分配给所需的属性,就好像它是公共属性一样。它实际上不会将其变为公共状态,但可以通过反射类进行修改。

AFAIK,前者如果不在字符串中创建临时类是不可能的,然后 eval()ing 这些,这就是模拟框架所做的。

通过反射,您可以忽略私有/受保护的修饰符,因此您可以直接使用该属性。如果这不是一个选择,恐怕你必须出卖你的灵魂:

eval("class EvilProxy extends Proxy implements Bar {}");
$foo->setBar(new EvilProxy());

(我假设Bar是动态的 - 否则您可以简单地静态创建 EvilProxy 类,而无需任何eval()

在您的示例中,调用

$foo->setBar($proxy);

将触发致命错误。如果您可以忍受严格的标准警告,例如:

严格的标准:TestFoo::setBar() 的声明应与 Foo::setBar(Bar $bar) 兼容

您可以覆盖该函数,然后通过反射更改父级私有属性:

class TestFoo extends Foo
{
    public function setBar(Proxy $bar)
    {
        $this->setPrivateParentProperty('bar', $bar);
    }
    private function setPrivateParentProperty($name, $value)
    {
        $refl     = new ReflectionObject($this);
        $property = $refl->getParentClass()->getProperty($name);
        $property->setAccessible(true);
        $property->setValue($this, $value);
    }
}

然后,您可以使用 TestFoo 类型而不是 Foo 类型(除非有接口、摘要或最终阻止这种情况):

$foo = new TestFoo();
$foo->setBar($proxy);

然而,正如严格的标准警告所显示的那样,这并没有真正考虑好。与以下方面进行比较:为什么 PHP 允许"不兼容"的构造函数?有关更详细的信息,为什么给出严格的标准错误。