链接
官网 WebSite
GitHub - Pimple

这是 Pimple 3.x 的文档。如果你正在使用 Pimple 1.x ,请查看 Pimple 1.x 文档。
阅读 Pimple 1.x 代码也是学习更多关于如何创建简单的依赖注入容器的好方法,新版本的 Pimple 更加关注性能。

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  

使用

创建一个容器实例

use Pimple\Container;$container = new Container();

与许多其他依赖注入容器一样,Pimple 管理两种不同类型的数据:服务参数

定义服务

服务是一个对象,它可以作为一个庞大系统的一部分,一些服务的例子:数据库连接,模板引擎,邮件服务。几乎所有的全局对象都可以成为一项服务。

服务通过匿名函数定义,返回一个对象的实例

// 定义一些服务
$container['session_storage'] = function ($c) {return new SessionStorage('SESSION_ID');
};$container['session'] = function ($c) {return new Session($c['session_storage']);
};

请注意,匿名函数可以访问当前容器实例,从而允许引用其他服务或参数。
由于只有在获取对象时才创建对象,因此定义的顺序无关紧要。

使用定义的服务也非常简单:

// 获取 session 对象
$session = $container['session'];// 上述调用大致等同于以下代码:
// $storage = new SessionStorage('SESSION_ID');
// $session = new Session($storage);

定义工厂服务

默认情况下,每次获得服务时,Pimple 都会返回相同的实例。如果要为所有调用返回不同的实例,请使用 factory() 方法包装你的匿名函数。

$container['session'] = $container->factory(function ($c) {return new Session($c['session_storage']);
});

现在,每次调用 $container['session'] 会返回一个新的 session 实例。

定义参数

定义参数允许从外部简化容器的配置并存储全局值

// 定义一些参数
$container['cookie_name'] = 'SESSION_ID';
$container['session_storage_class'] = 'SessionStorage';

你现在可以很轻松的通过重写 session_storage_class 参数而不是重新定义服务定义来更改 cookie 名称。

保护参数

由于 Pimple 将匿名函数看作服务定义,因此需要使用 protect() 方法将匿名函数包装为参数:

$container['random_func'] = $container->protect(function () {return rand();
});

修改已经定义的服务

在某些情况下,你可能需要在定义服务定义后修改它。在你的服务被创建后,你可以使用 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;
});

第一个参数是要扩展的服务的名称,第二个参数是访问对象实例和容器的函数。

扩展容器

如果你反复使用相同的库,可能希望将一个项目中的某些服务重用到下一个项目,通过实现 Pimple\ServiceProviderInterface 接口,打包你的服务到 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());

获取服务创建方法

当你访问一个对象时,Pimple 自动调用你定义的匿名函数,为你创建服务对象。如果你想获得这个函数的原始访问权限,你可以使用 raw()方法:

$container['session'] = function ($c) {return new Session($c['session_storage']);
};$sessionFunction = $container->raw('session');

PSR-11 兼容性

由于历史原因,Container 类没有实现 PSR-11 ContainerInterface。然而,Pimple 提供了一个辅助类,它可以让你从 Pimple 容器类中解耦你的代码

PSR-11 容器类

Pimple\Psr11\Container 类允许你使用 Psr\Container\ContainerInterface 方法访问 Pimple 容器的内容:

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 服务定位

有时候,服务需要访问其他几个服务,而不必确定所有这些服务都将被实际使用。在这些情况下,你可能希望懒加载这些服务。

传统的解决方案是注入整个服务容器来获得真正需要的服务。但是,这不被推荐,因为它使服务对应用程序的其他部分的访问过于宽泛,并且隐藏了它们的实际依赖关系。

ServiceLocator 旨在通过访问一组预定义的服务来解决此问题,同时仅在实际需要时才实例化它们。
它还允许你以不同于用于注册的名称提供服务。例如,你可能希望使用一个对象,该对象期望 EventDispatcherInterface 实例在名称 event_dispatcher 下可用,而你的事件分派器已在名称 dispatcher 下注册

use Monolog\Logger;
use Pimple\Psr11\ServiceLocator;
use Psr\Container\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;class MyService
{/*** "logger" must be an instance of Psr\Log\LoggerInterface* "event_dispatcher" must be an instance of Symfony\Component\EventDispatcher\EventDispatcherInterface*/private $services;public function __construct(ContainerInterface $services){$this->services = $services;}
}$container['logger'] = function ($c) {return new Monolog\Logger();
};
$container['dispatcher'] = function () {return new EventDispatcher();
};$container['service'] = function ($c) {$locator = new ServiceLocator($c, array('logger', 'event_dispatcher' => 'dispatcher'));return new MyService($locator);
};

懒懒的引用一系列服务

在数组中传递一组服务实例可能会导致效率低下,因为如果使用集合的类只需要在稍后调用它的方法时对其进行迭代即可。如果集合中存储的其中一个服务与使用该服务的类之间存在循环依赖关系,则也会导致问题。

ServiceIterator 类可以帮助你解决这些问题。它在实例化过程中接收服务名称列表,并在迭代时检索服务

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 框架的创建者 Fabien Potencier 写的 ,Pimple 是在 MIT 协议下发布的。

原创文章,欢迎转载。转载请注明出处,谢谢。
原文链接地址:http://dryyun.com/2018/04/17/...
作者: dryyun
发表日期: 2018-04-17 14:30:29

Pimple - 一个简单的 PHP 依赖注入容器相关推荐

  1. asp.net core自定义依赖注入容器,替换自带容器

    依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...

  2. 又一个强大的PHP5.3依赖注入容器

    简单的服务容器 一个简单的 php 5.3 依赖注入容器. 项目地址:https://github.com/godruoyi/easy-container Why 目前比较流行的 PHP 容器: Pi ...

  3. 依赖注入容器Unity Application Block快速入门

    概述 Unity是微软模式与实践团队开发的一个轻量级.可扩展的依赖注入容器,之前我也有过一篇文章<Enterprise Library 4.0中的依赖注入容器(Unity)预览>对其做过介 ...

  4. 依赖注入容器Autofac的详解[转]

    依赖注入容器Autofac的详解 发表于 2011 年 09 月 22 日 由 renfengbin 分享到:GMAIL邮箱         Hotmail邮箱 delicious digg Auto ...

  5. spring依赖注入_Spring源码阅读:Spring依赖注入容器

    依赖注入 依赖注入是Spring框架最核心的能力,Spring框架提供的AOP,WebMVC等其它功能都是以依赖注入容器作为基础构建的,Spring依赖注入容器类似于一个用于组装对象的框架内核,任何应 ...

  6. ASP.NET Core依赖注入容器中的动态服务注册

    介绍 在ASP.NET Core中,每当我们将服务作为依赖项注入时,都必须将此服务注册到ASP.NET Core依赖项注入容器.但是,一个接一个地注册服务不仅繁琐且耗时,而且容易出错.因此,在这里,我 ...

  7. python需要依赖注入吗_是否需要使用依赖注入容器?

    译文首发于 是否需要使用依赖注入容器?,转载请注明出处. 本文是依赖注入(Depeendency Injection)系列教程的第 2 篇文章,本系列教程主要讲解如何使用 PHP 实现一个轻量级服务容 ...

  8. 依赖注入:一个Mini版的依赖注入框架

    前面的章节中,我们从纯理论的角度对依赖注入进行了深入论述,我们接下来会对.NET Core依赖注入框架进行单独介绍.为了让读者朋友能够更好地理解.NET Core依赖注入框架的设计与实现,我们按照类似 ...

  9. 如何检查服务已在依赖注入容器中注册

    前言 依赖关系注入(DI),是一种在类及其依赖项之间实现控制反转(IoC)的技术.在ASP.NET Core中,依赖关系注入是"一等公民",被大量使用. 但是有时,我们仅仅只需要知 ...

最新文章

  1. idea2019配置gradle详解_Java学习之——Gradle的安装配置、IDEA中创建Gradle的Java项目...
  2. ie8 script445: 对象不支持此操作_经验总结:上海增值税认证勾选安装和操作步骤...
  3. NLP之TEA:基于SnowNLP实现自然语言处理之对输入文本进行情感分析(分词→词性标注→拼音简繁转换→情感分析→测试)
  4. iOS使用 xcconfig配置文件的若干坑
  5. 基于AVS2的图片容器——TPG:现状与改进之路
  6. 最大功率点跟踪测试软件,最大功率点跟踪
  7. python网络爬虫系列(九)——打码平台的使用
  8. MongoDB基本概念和常用操作(二)
  9. CSS-float详解,深入理解clear:both[转+部分原创]
  10. docker java 最小镜像_Docker多步构建更小的Java镜像
  11. 【java笔记】线程(2):多线程的原理
  12. Oracle用户可要顶住了:准备好大规模补丁工作!以修补多达 433 个的新安全漏洞...
  13. OpenNebula概述
  14. smtp发送邮件和pop3收取邮件
  15. node爬取cnode首页数据
  16. c语言图像峰值信噪比,PSNRSSIM
  17. 怎么在本地运行java项目,eclipse怎么运行java web项目?
  18. 拨号上网、ISDN、ADSL、光纤上网比较
  19. scoop下载安装教程,无报错,超简单。
  20. php仿制网站,如何仿制网站(一模一样),制造后台管理系统CMS

热门文章

  1. sqlplus执行mysql_在SQLPLUS启动和停止Oracle数据库
  2. flash期末作业成品_基于“新工科”的工科物理作业模式研究
  3. 使用vant时 tab栏中出现 van-tabs怎么省略号怎么解决
  4. Redis与其他缓存框架的对比
  5. 计算机专业的分支,计算机专业分支(转载)
  6. python中global的用法
  7. 我眼中的软件测试,交互设计师眼中的软件测试
  8. android 隐藏闹钟通知,redis环境搭建
  9. 2018年4月java自考真题,全国2018年4月自考互联网数据库考试真题
  10. php files上传错误,php-PHP上传文件的问题$_FILES['file']['error']