假设:
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
。)
注意:是的,这是奇怪的东西,我期待对此发表评论,但请留下“答案”以获得问题的实际答案。这不是生产代码。
答案 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?进行比较,以获取更详细的信息,说明为什么会出现严格的标准错误。