php中依赖注入深入理解
发布:smiling 来源: PHP粉丝网 添加日期:2018-10-13 14:15:49 浏览: 评论:0
PHP程序员如何理解依赖注入容器(dependency injection container)
背景知识
传统的思路是应用程序用到一个Foo类,就会创建Foo类并调用Foo类的方法,假如这个方法内需要一个Bar类,就会创建Bar类并调用Bar类的方法,而这个方法内需要一个Bim类,就会创建Bim类,接着做些其它工作。
- <?php
- // 代码【1】
- class Bim
- {
- public function doSomething()
- {
- echo __METHOD__, '|';
- }
- }
- class Bar
- {
- public function doSomething()
- {
- $bim = new Bim();
- $bim->doSomething();
- echo __METHOD__, '|';
- }
- }
- class Foo
- {
- public function doSomething()
- {
- $bar = new Bar();
- $bar->doSomething();
- echo __METHOD__;
- }
- }
- $foo = new Foo();
- $foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething
使用依赖注入的思路是应用程序用到Foo类,Foo类需要Bar类,Bar类需要Bim类,那么先创建Bim类,再创建Bar类并把Bim注入,再创建Foo类,并把Bar类注入,再调用Foo方法,Foo调用Bar方法,接着做些其它工作。
- <?php
- // 代码【2】
- class Bim
- {
- public function doSomething()
- {
- echo __METHOD__, '|';
- }
- }
- class Bar
- {
- private $bim;
- public function __construct(Bim $bim)
- {
- $this->bim = $bim;
- }
- public function doSomething()
- {
- $this->bim->doSomething();
- echo __METHOD__, '|';
- }
- }
- class Foo
- {
- private $bar;
- public function __construct(Bar $bar)
- {
- $this->bar = $bar;
- }
- public function doSomething()
- {
- $this->bar->doSomething();
- echo __METHOD__;
- }
- }
- $foo = new Foo(new Bar(new Bim()));
- $foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething
这就是控制反转模式。依赖关系的控制反转到调用链的起点。这样你可以完全控制依赖关系,通过调整不同的注入对象,来控制程序的行为。例如Foo类用到了memcache,可以在不修改Foo类代码的情况下,改用redis。
使用依赖注入容器后的思路是应用程序需要到Foo类,就从容器内取得Foo类,容器创建Bim类,再创建Bar类并把Bim注入,再创建Foo类,并把Bar注入,应用程序调用Foo方法,Foo调用Bar方法,接着做些其它工作.
总之容器负责实例化,注入依赖,处理依赖关系等工作。
代码演示 依赖注入容器 (dependency injection container)
通过一个最简单的容器类来解释一下,这段代码来自 Twittee
- <?php
- class Container
- {
- private $s = array();
- function __set($k, $c)
- {
- $this->s[$k] = $c;
- }
- function __get($k)
- {
- return $this->s[$k]($this);
- }
- }
这段代码使用了魔术方法,在给不可访问属性赋值时,__set() 会被调用。读取不可访问属性的值时,__get() 会被调用。
- <?php
- $c = new Container();
- $c->bim = function () {
- return new Bim();
- };
- $c->bar = function ($c) {
- return new Bar($c->bim);
- };
- $c->foo = function ($c) {
- return new Foo($c->bar);
- }; //phpfensi.com
- // 从容器中取得Foo
- $foo = $c->foo;
- $foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething
这段代码使用了匿名函数
再来一段简单的代码演示一下,容器代码来自simple di container
- <?php
- class IoC
- {
- protected static $registry = [];
- public static function bind($name, Callable $resolver)
- {
- static::$registry[$name] = $resolver;
- }
- public static function make($name)
- {
- if (isset(static::$registry[$name])) {
- $resolver = static::$registry[$name];
- return $resolver();
- }
- throw new Exception('Alias does not exist in the IoC registry.');
- }
- }
- IoC::bind('bim', function () {
- return new Bim();
- });
- IoC::bind('bar', function () {
- return new Bar(IoC::make('bim'));
- });
- IoC::bind('foo', function () {
- return new Foo(IoC::make('bar'));
- });
- // 从容器中取得Foo
- $foo = IoC::make('foo');
- $foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething
这段代码使用了后期静态绑定
依赖注入容器 (dependency injection container) 高级功能
真实的dependency injection container会提供更多的特性,如:
自动绑定(Autowiring)或 自动解析(Automatic Resolution)
注释解析器(Annotations)
延迟注入(Lazy injection)
下面的代码在Twittee的基础上,实现了Autowiring。
- <?php
- class Bim
- {
- public function doSomething()
- {
- echo __METHOD__, '|';
- }
- }
- class Bar
- {
- private $bim;
- public function __construct(Bim $bim)
- {
- $this->bim = $bim;
- }
- public function doSomething()
- {
- $this->bim->doSomething();
- echo __METHOD__, '|';
- }
- }
- class Foo
- {
- private $bar;
- public function __construct(Bar $bar)
- {
- $this->bar = $bar;
- }
- public function doSomething()
- {
- $this->bar->doSomething();
- echo __METHOD__;
- }
- }
- class Container
- {
- private $s = array();
- public function __set($k, $c)
- {
- $this->s[$k] = $c;
- }
- public function __get($k)
- {
- // return $this->s[$k]($this);
- return $this->build($this->s[$k]);
- }
- /**
- * 自动绑定(Autowiring)自动解析(Automatic Resolution)
- *
- * @param string $className
- * @return object
- * @throws Exception
- */
- public function build($className)
- {
- // 如果是匿名函数(Anonymous functions),也叫闭包函数(closures)
- if ($className instanceof Closure) {
- // 执行闭包函数,并将结果
- return $className($this);
- }
- /** @var ReflectionClass $reflector */
- $reflector = new ReflectionClass($className);
- // 检查类是否可实例化, 排除抽象类abstract和对象接口interface
- if (!$reflector->isInstantiable()) {
- throw new Exception("Can't instantiate this.");
- }
- /** @var ReflectionMethod $constructor 获取类的构造函数 */
- $constructor = $reflector->getConstructor();
- // 若无构造函数,直接实例化并返回
- if (is_null($constructor)) {
- return new $className;
- }
- // 取构造函数参数,通过 ReflectionParameter 数组返回参数列表
- $parameters = $constructor->getParameters();
- // 递归解析构造函数的参数
- $dependencies = $this->getDependencies($parameters);
- // 创建一个类的新实例,给出的参数将传递到类的构造函数。
- return $reflector->newInstanceArgs($dependencies);
- }
- /**
- * @param array $parameters
- * @return array
- * @throws Exception
- */
- public function getDependencies($parameters)
- {
- $dependencies = [];
- /** @var ReflectionParameter $parameter */
- foreach ($parameters as $parameter) {
- /** @var ReflectionClass $dependency */
- $dependency = $parameter->getClass();
- if (is_null($dependency)) {
- // 是变量,有默认值则设置默认值
- $dependencies[] = $this->resolveNonClass($parameter);
- } else {
- // 是一个类,递归解析
- $dependencies[] = $this->build($dependency->name);
- }
- }
- return $dependencies;
- }
- /**
- * @param ReflectionParameter $parameter
- * @return mixed
- * @throws Exception
- */
- public function resolveNonClass($parameter)
- {
- // 有默认值则返回默认值
- if ($parameter->isDefaultValueAvailable()) {
- return $parameter->getDefaultValue();
- }
- throw new Exception('I have no idea what to do here.');
- }
- }
- // ----
- $c = new Container();
- $c->bar = 'Bar';
- $c->foo = function ($c) {
- return new Foo($c->bar);
- };
- // 从容器中取得Foo
- $foo = $c->foo;
- $foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething
- // ----
- $di = new Container();
- $di->foo = 'Foo';
- /** @var Foo $foo */
- $foo = $di->foo;
- var_dump($foo);
- /*
- Foo#10 (1) {
- private $bar =>
- class Bar#14 (1) {
- private $bim =>
- class Bim#16 (0) {
- }
- }
- }
- */
- $foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething
以上代码的原理参考PHP官方文档:反射,PHP 5 具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。
Tags: php依赖注入 php注入
- 上一篇:用php实现php代码的加密解密类分享
- 下一篇:PHP调用linux外部命令的例子
相关文章
- ·PHP基于反射机制实现自动依赖注入的方法详解(2021-08-22)
- ·PHP依赖注入原理与用法分析(2021-10-26)
- ·PHP依赖注入原理与用法分析(2021-10-26)
- ·PHP经典设计模式之依赖注入定义与用法详解(2021-11-22)
- ·php反射学习之依赖注入示例(2021-11-25)
- ·php中的依赖注入实例详解(2021-12-11)
- ·常用的SQL注入攻击方法总结(2014-08-22)
- ·ASP/PHP sql注入语句整理大全(2018-10-15)
- ·PHP防止SQL注入的例子(2018-10-16)
- ·深入分析PHP对象注入详解(2018-10-16)
- ·PHP序列化/对象注入漏洞分析(2021-07-29)
- ·浅析PHP类的反射来实现依赖注入过程(2021-09-03)
推荐文章
热门文章
最新评论文章
- 写给考虑创业的年轻程序员(10)
- PHP新手上路(一)(7)
- 惹恼程序员的十件事(5)
- PHP邮件发送例子,已测试成功(5)
- 致初学者:PHP比ASP优秀的七个理由(4)
- PHP会被淘汰吗?(4)
- PHP新手上路(四)(4)
- 如何去学习PHP?(2)
- 简单入门级php分页代码(2)
- php中邮箱email 电话等格式的验证(2)