Pimple - 一个简单的 PHP 依赖注入容器
官網(wǎng) WebSite
GitHub - Pimple 這是 Pimple 3.x 的文檔。如果你正在使用 Pimple 1.x ,請查看 Pimple 1.x 文檔。
閱讀 Pimple 1.x 代碼也是學習更多關(guān)于如何創(chuàng)建簡單的依賴注入容器的好方法,新版本的 Pimple 更加關(guān)注性能。
Pimple - 一個簡單的 PHP 依賴注入容器
安裝
在你的項目中使用 Pimple 之前,將其添加到你的 composer.json 文件中:
$ ./composer.phar require pimple/pimple ~3.0
另外,Pimple 也可作為 PHP C 擴展使用:
$ git clone https://github.com/silexphp/Pimple $ cd Pimple/ext/pimple $ phpize $ ./configure $ make $ make install使用
創(chuàng)建一個容器實例
use Pimple\Container;$container = new Container();與許多其他依賴注入容器一樣,Pimple 管理兩種不同類型的數(shù)據(jù):服務(wù)和參數(shù)
定義服務(wù)
服務(wù)是一個對象,它可以作為一個龐大系統(tǒng)的一部分,一些服務(wù)的例子:數(shù)據(jù)庫連接,模板引擎,郵件服務(wù)。幾乎所有的全局對象都可以成為一項服務(wù)。
服務(wù)通過匿名函數(shù)定義,返回一個對象的實例
// 定義一些服務(wù) $container['session_storage'] = function ($c) {return new SessionStorage('SESSION_ID'); };$container['session'] = function ($c) {return new Session($c['session_storage']); };請注意,匿名函數(shù)可以訪問當前容器實例,從而允許引用其他服務(wù)或參數(shù)。
由于只有在獲取對象時才創(chuàng)建對象,因此定義的順序無關(guān)緊要。
使用定義的服務(wù)也非常簡單:
// 獲取 session 對象 $session = $container['session'];// 上述調(diào)用大致等同于以下代碼: // $storage = new SessionStorage('SESSION_ID'); // $session = new Session($storage);定義工廠服務(wù)
默認情況下,每次獲得服務(wù)時,Pimple 都會返回相同的實例。如果要為所有調(diào)用返回不同的實例,請使用 factory() 方法包裝你的匿名函數(shù)。
$container['session'] = $container->factory(function ($c) {return new Session($c['session_storage']); });現(xiàn)在,每次調(diào)用 $container['session'] 會返回一個新的 session 實例。
定義參數(shù)
定義參數(shù)允許從外部簡化容器的配置并存儲全局值
// 定義一些參數(shù) $container['cookie_name'] = 'SESSION_ID'; $container['session_storage_class'] = 'SessionStorage';你現(xiàn)在可以很輕松的通過重寫 session_storage_class 參數(shù)而不是重新定義服務(wù)定義來更改 cookie 名稱。
保護參數(shù)
由于 Pimple 將匿名函數(shù)看作服務(wù)定義,因此需要使用 protect() 方法將匿名函數(shù)包裝為參數(shù):
$container['random_func'] = $container->protect(function () {return rand(); });修改已經(jīng)定義的服務(wù)
在某些情況下,你可能需要在定義服務(wù)定義后修改它。在你的服務(wù)被創(chuàng)建后,你可以使用 extend() 方法添加額外的代碼:
$container['session_storage'] = function ($c) {return new $c['session_storage_class']($c['cookie_name']); };$container->extend('session_storage', function ($storage, $c) {$storage->...();return $storage; });第一個參數(shù)是要擴展的服務(wù)的名稱,第二個參數(shù)是訪問對象實例和容器的函數(shù)。
擴展容器
如果你反復(fù)使用相同的庫,可能希望將一個項目中的某些服務(wù)重用到下一個項目,通過實現(xiàn) Pimple\ServiceProviderInterface 接口,打包你的服務(wù)到 Provider 程序中
use Pimple\Container;class FooProvider implements Pimple\ServiceProviderInterface {public function register(Container $pimple){// register some services and parameters// on $pimple} }然后,在容器上注冊 Provider
$pimple->register(new FooProvider());獲取服務(wù)創(chuàng)建方法
當你訪問一個對象時,Pimple 自動調(diào)用你定義的匿名函數(shù),為你創(chuàng)建服務(wù)對象。如果你想獲得這個函數(shù)的原始訪問權(quán)限,你可以使用 raw()方法:
$container['session'] = function ($c) {return new Session($c['session_storage']); };$sessionFunction = $container->raw('session');PSR-11 兼容性
由于歷史原因,Container 類沒有實現(xiàn) PSR-11 ContainerInterface。然而,Pimple 提供了一個輔助類,它可以讓你從 Pimple 容器類中解耦你的代碼
PSR-11 容器類
Pimple\Psr11\Container 類允許你使用 Psr\Container\ContainerInterface 方法訪問 Pimple 容器的內(nèi)容:
use Pimple\Container; use Pimple\Psr11\Container as PsrContainer;$container = new Container(); $container['service'] = function ($c) {return new Service(); }; $psr11 = new PsrContainer($container);$controller = function (PsrContainer $container) {$service = $container->get('service'); }; $controller($psr11);使用 PSR-11 服務(wù)定位
有時候,服務(wù)需要訪問其他幾個服務(wù),而不必確定所有這些服務(wù)都將被實際使用。在這些情況下,你可能希望懶加載這些服務(wù)。
傳統(tǒng)的解決方案是注入整個服務(wù)容器來獲得真正需要的服務(wù)。但是,這不被推薦,因為它使服務(wù)對應(yīng)用程序的其他部分的訪問過于寬泛,并且隱藏了它們的實際依賴關(guān)系。
ServiceLocator 旨在通過訪問一組預(yù)定義的服務(wù)來解決此問題,同時僅在實際需要時才實例化它們。
它還允許你以不同于用于注冊的名稱提供服務(wù)。例如,你可能希望使用一個對象,該對象期望 EventDispatcherInterface 實例在名稱 event_dispatcher 下可用,而你的事件分派器已在名稱 dispatcher 下注冊
懶懶的引用一系列服務(wù)
在數(shù)組中傳遞一組服務(wù)實例可能會導(dǎo)致效率低下,因為如果使用集合的類只需要在稍后調(diào)用它的方法時對其進行迭代即可。如果集合中存儲的其中一個服務(wù)與使用該服務(wù)的類之間存在循環(huán)依賴關(guān)系,則也會導(dǎo)致問題。
ServiceIterator 類可以幫助你解決這些問題。它在實例化過程中接收服務(wù)名稱列表,并在迭代時檢索服務(wù)
use Pimple\Container; use Pimple\ServiceIterator;class AuthorizationService {private $voters;public function __construct($voters){$this->voters = $voters;}public function canAccess($resource){foreach ($this->voters as $voter) {if (true === $voter->canAccess($resource) {return true;}}return false;} }$container = new Container();$container['voter1'] = function ($c) {return new SomeVoter(); } $container['voter2'] = function ($c) {return new SomeOtherVoter($c['auth']); } $container['auth'] = function ($c) {return new AuthorizationService(new ServiceIterator($c, array('voter1', 'voter2')); }誰在支持 Pimple ?
Pimple 是由 Symfony 框架的創(chuàng)建者 Fabien Potencier 寫的 ,Pimple 是在 MIT 協(xié)議下發(fā)布的。
原創(chuàng)文章,歡迎轉(zhuǎn)載。轉(zhuǎn)載請注明出處,謝謝。原文鏈接地址:http://dryyun.com/2018/04/17/...
作者: dryyun
發(fā)表日期: 2018-04-17 14:30:29
總結(jié)
以上是生活随笔為你收集整理的Pimple - 一个简单的 PHP 依赖注入容器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通过xadmin或者suit-v2快速搭
- 下一篇: ES-PHP向ES批量添加文档报No a