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

时间:2013-01-29 21:48:35

标签: php reflection type-hinting

假设:

class Foo {
    private $bar;

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

是否有 任何 方式使用不是 setBar()的实例来调用Bar

$proxy = new Proxy();

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

// with
class Proxy  {
}

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


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

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

3 个答案:

答案 0 :(得分:1)

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

后者可以使用ReflectionProperty::setAccessible,然后您可以为所需的属性分配任何内容,就像它是公共属性一样。它实际上不会将其公之于众,但它可以通过反射类进行修改。

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

答案 1 :(得分:0)

使用反射,您可以忽略私有/受保护修饰符,因此您可以直接转到该属性。如果那不是一个选择,我担心你必须卖掉你的灵魂:

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

(我认为Bar是动态的 - 否则您只需静态创建EvilProxy类,而不需要任何eval()。)

答案 2 :(得分:0)

在您的示例中调用

$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);

然而,正如严格的标准警告所示,这并不是很好。与Why does PHP allow “incompatible” constructors?进行比较,以获取更详细的信息,说明为什么会出现严格的标准错误。