3

鉴于:

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


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

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

4

3 回答 3

1

是否需要调用 setBar(),或者您可以通过设置私有 $bar 属性来解决吗?

后者可以使用ReflectionProperty::setAccessible,然后您可以将任何内容分配给您想要的属性,就好像它是公共属性一样。它实际上不会将其公开,但可以通过反射类对其进行修改。

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

于 2013-01-29T23:05:34.223 回答
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);

然而,正如严格标准警告所显示的那样,这并不是经过深思熟虑的。比较一下:为什么 PHP 允许“不兼容”的构造函数?有关为什么给出严格标准错误的更详细信息。

于 2013-03-31T14:08:28.387 回答
0

通过反射,您可以忽略私有/受保护的修饰符,因此您可以直接获取属性。如果这不是一个选择,我担心你不得不出卖你的灵魂:

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

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

于 2013-02-05T14:21:27.170 回答