php中依赖注入深入认识
发布时间:2022-07-02 17:16:42 所属栏目:PHP教程 来源:互联网
导读:PHP程序员如何理解依赖注入容器(dependency injection container) 背景知识 传统的思路是应用程序用到一个Foo类,就会创建Foo类并调用Foo类的方法,假如这个方法内需要一个Bar类,就会创建Bar类并调用Bar类的方法,而这个方法内需要一个Bim类,就会创建Bim类
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方法,接着做些其它工作. { $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 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会提供更多的特性,如: 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 * @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(); * @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) { /** @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 提供了方法来取出函数、类和方法中的文档注释。 (编辑:云计算网_泰州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |