我试图找出Phalcon \ Di \ Injectable如何工作的逻辑,我有点困惑。
class Foo extends \Phalcon\DI\Injectable
{
public function bar()
{
return $this->config->test;
}
}
$di = new \Phalcon\DI\FactoryDefault();
$di->set('config', function () use ($di) {
return new \Phalcon\Config(['test' => 'test']);
});
\Phalcon\DI::setDefault($di);
// test 1 : expecting "test"
$bla = new Foo();
$bla->setDI($di);
var_dump($bla->bar());
// test 2 : expecting error "test" undefined
$di->set('config', function() {
return new \Phalcon\Config();
});
var_dump($bla->bar());
// test 3 : expecting error "test" undefined
$bla2 = new Foo();
$bla2->setDI($di);
var_dump($bla2->bar());
脚本的实际输出是
string(4) "test"
string(4) "test"
string(4) "test"
所以看起来第一次注入依赖项后,它们永远不会得到更新。 DI容器引用更新的对象。如果将方法声明更改为
public function bar()
{
return $this->di->getConfig()->test;
}
它的行为符合预期。
问题是,这是一个错误还是我误解了Di \ Injectable背后的逻辑?
答案 0 :(得分:0)
长话短说,您可以修改DI()
组件下的对象,但可能会发生棘手。
一旦用DI():: set()声明对象,它可能会保持未实例化,直到第一次使用。作为证明:
$di->set('config', function () use ($di) {
return new \Phalcon\Config(['test' => 'test']);
});
$di->set('config', function () use ($di) {
return new \Phalcon\Config(['test' => 'testTwo']);
});
$cnf = $di->get('config'); // get = instantiation
var_dump($cnf);
结果你会得到:
object(Phalcon\Config)[24]
public 'test' => string 'testTwo' (length=7)
它将保持这种方式。有例外。
如果您想拥有例如。配置服务在运行时可配置,你应该知道set()和setShared()之间的区别。使用set()创建的服务是使用声明的匿名函数重新创建的,并且很难更改它。对于您的示例,请参阅代码段:
$di->set('config', function () use ($di) {
return new \Phalcon\Config(['test' => 'test']);
});
// context related instance
$cnf = $di->get('config');
$cnf->offsetSet('test', 'testTwo');
var_dump($cnf);
// default instance
$cnf = $di->get('config');
var_dump($cnf);
将导致转储两个不同的结果。但是一旦使用setShared()声明服务,您将再次获取依赖于先前对象操作的值:
$di->setShared('config', function () use ($di) {
return new \Phalcon\Config(['test' => 'test']);
});
$cnf = $di->get('config');
$cnf->offsetSet('test', 'testTwo');
var_dump($cnf);
$cnf = $di->get('config');
var_dump($cnf);
因为服务未重新实例化。如果您发现您愿意将DI()服务替换为其他服务,您必须花时间找到适当的DI()(因为服务可能有其独有的依赖列表)来做到这一点,但它可能:
$di->set('config', function () use ($di) {
return new \Phalcon\Config(['test' => 'testError']);
});
$cnf = $di->get('config');
var_dump($cnf);
$di->set('config', new \Phalcon\Config(['test' => 'testProper']));
$cnf = $di->get('config');
var_dump($cnf);
也可以使用setShared()。结果作为证据:
object(Phalcon\Config)[25]
public 'test' => string 'testError' (length=9)
object(Phalcon\Config)[26]
public 'test' => string 'testProper' (length=10)
希望它能为某些事情付出代价。有用的链接:Dependency Injection manual。
随Phalcon 1.3.2提供。
test1和test2之间的示例正在按预期工作。一旦你使用$this->config
,它就会被声明的闭包实例化,并保持这种方式。但你可以通过稍微调整你的bar()函数来获得你想要的行为:
public function bar()
{
$di = $this->getDI();
return $di->get('config')->test;
}
这样,因为如果对象仅在Foo上下文中被实例化是不明确的,Phalcon将根据你在DI :: set()中的闭包生成新的Object。这将抛出你期望的' undefined'错误。