簡體   English   中英

Phalcon \\ DI \\ Injectable在運行時不更新服務

[英]Phalcon\DI\Injectable not updating services during runtime

我試圖弄清楚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背后的邏輯?

長話短說,您確實可以在DI()組件下修改對象,但這可能會很棘手。

1.實例化時間

一旦用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)

它將保持這種方式。 有例外。

2. DI:set()和DI:setShared()

如果您想擁有例如。 可以在運行時配置的config服務,您應該了解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)

希望它使一些事情變得愉快。 有用的鏈接: 依賴注入手冊

提供Phalcon 1.3.2。

3編輯-重新實例化:

您在test1和test2之間的示例按預期工作。 一旦使用$this->config它將使用聲明的閉包實例化,並保持這種方式。 但是您可以通過修改一下bar()函數來獲得所需的行為:

public function bar()
{
    $di = $this->getDI();
    return $di->get('config')->test;
}

這樣,如果僅在Foo上下文中實例化對象是模棱兩可的,Phalcon將根據您在DI :: set()中的閉包生成新的Object。 這將引發您預期的“未定義”錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM