这篇文章是关于一般依赖关系注入和在PHP中实现依赖注入容器系列的第一部分。
坚守“ 做人真诚 · 做事靠谱 · 口碑至上 · 高效敬业 ”的价值观,专业网站建设服务10余年为成都成都石雕小微创业公司专业提供企业网站制作营销网站建设商城网站建设手机网站建设小程序网站建设网站改版,从内容策划、视觉设计、底层架构、网页布局、功能开发迭代于一体的高端网站建设服务。今天我不会谈论容器然而我想以一些具体的示例介绍依赖注入的概念希望说明尝试去解决问题和它给开发者带来的好处。如果你已经知道依赖注入的概念你可以略过本文等待下一篇。
依赖注入或许是我所知道的最简单的设计模式之一。或许你已经使用过依赖注入。但它是解释最困难的一个。我认为部分原因在于大多数介绍依赖注入的时候使用了没有意义的示例。我试图想出更符合PHP世界的例子由于PHP这种语言主要是用来做WEB开发的让我们举一个简单的WEB例子。
为了克服HTTP协议的无状态性web应用程序需要一种方法来存储web请求之间的用户信息。当然通过使用一个cookie或者甚至更好的方式通过使用PHP内置的会话机制(session)实现是非常简单的。
$_SESSION['language'] = 'fr';上面的代码中用语言会话变量存储用户的语言。因此针对同一个用户的后续请求在超全局变量$_SESSION数组中的语言是有效的。
$user_language = $_SESSION['language'];在面向对象的世界中依赖关系注入才有意义让我们假设我们有一个SessionStorage 类封装了PHP的会话机制
class SessionStorage { function __construct($cookieName = 'PHP_SESS_ID') { session_name($cookieName); session_start(); } function set($key, $value) { $_SESSION[$key] = $value; } function get($key) { return $_SESSION[$key]; } // ... }... 和一个提供了更高级别接口的用户类
class User { protected $storage; function __construct() { $this->storage = new SessionStorage(); } function setLanguage($language) { $this->storage->set('language', $language); } function getLanguage() { return $this->storage->get('language'); } // ... }这些类是足够简单的使用User类相比更容易
$user = new User(); $user->setLanguage('fr'); $user_language = $user->getLanguage();全部都很好...直到你想要更多的灵活性。如果你想要修改实例会话cookie的名称下面是一些随机的可能性
·在User类里面是硬编码的名称在他的SessionStorage 构造函数中:
class User { function __construct() { $this->storage = new SessionStorage('SESSION_ID'); } // ... }在User类的外面定义一个常量
class User { function __construct() { $this->storage = new SessionStorage(STORAGE_SESSION_NAME); } // ... } define('STORAGE_SESSION_NAME', 'SESSION_ID');添加会话的名称session name作为User类的构造函数的参数
class User { function __construct($sessionName) { $this->storage = new SessionStorage($sessionName); } // ... } $user = new User('SESSION_ID');为存储类SessionStorage添加一个选项数组
class User { function __construct($storageOptions) { $this->storage = new SessionStorage($storageOptions['session_name']); } // ... } $user = new User(array('session_name' => 'SESSION_ID'));所有的这些选择都是相当糟糕的。在User类中的硬编码会话名称session name并没有真正解决问题你不能轻易改变想法以后而无需再次更改User类。使用一个常量之所以糟糕的因为User类现在依赖一个常量被设置。传递会话名称session name作为一个参数或者作为一个选项数组是或许是最好的解决方法但它仍然很糟糕。用不相关的参数给对象本身打乱了User类构造函数的参数。
但是仍然有问题不能被解决我怎么才能更改SessionStorage 类呢例如为了方便测试将它替换为一个假对象。或者也许是因为你想要在数据库表中或者内存中存储会话sessions。当前实现是不可能的除非你修改User类。加入依赖注入而不是在User类里面建立SessionStorage 对象让我们在User对象通过传递一个构造参数注入SessionStorage对象
class User { function __construct($storage) { $this->storage = $storage; } // ... }这就是依赖注入。仅此而已使用User类现在多了一点包括你首先需要建立SessionStorage 对象
$storage = new SessionStorage('SESSION_ID'); $user = new User($storage);现在配置会话存储对象session storage object是非常简单的和替换会话存储类也是非常容易。并且由于关注点的分离User类没有改变一切都是可能的。
Pico Container website介绍的依赖注入就像这样的
"Dependency Injection iswhere components are given their dependencies through their constructors, methods, or directly into fields."
“依赖注入是其中的组件通过他们的构造器、方法、或者直接到字段的方式”给与他们的依赖关系。
至于其他的设计模式依赖注入也有一些反模式。Pico Container website介绍了其中的一些。
依赖注入不局限于构造函数注入:
·构造器注入:
class User { function __construct($storage) { $this->storage = $storage; } // ... }·Setter注入:
class User { function setSessionStorage($storage) { $this->storage = $storage; } // ... }·属性注入:
class User { public $sessionStorage; } $user->sessionStorage = $storage;作为经验法则构造器所需要的依赖关系是最好的就像在我们的例子中setter注入最适合可选的依赖关系比如像一个缓存实例对象。如今最现代化的PHP框架大量使用了依赖注入提供了一组解耦但内聚的组件。
// symfony: A constructor injection example $dispatcher = new sfEventDispatcher(); $storage = new sfMySQLSessionStorage(array('database' => 'session', 'db_table' => 'session')); $user = new sfUser($dispatcher, $storage, array('default_culture' => 'en')); // Zend Framework: A setter injection example $transport = new Zend_Mail_Transport_Smtp('smtp.gmail.com', array( 'auth'=> 'login', 'username' => 'foo', 'password' => 'bar', 'ssl'=> 'ssl', 'port'=> 465, )); $mailer = new Zend_Mail(); $mailer->setDefaultTransport($transport);如果你有兴趣学习更多关于依赖注入我强烈建议你阅读Martin Fowler introduction或者优秀的Jeff More presentation。你还可以去看看我去年给依赖注入做的介绍presentation在这篇文章中谈论的在里面讲了更多在例子上的细节。
今天就到这了。我希望你现在对依赖注入的概念有一个更好的理解。在本系列的下一篇文章我会谈谈依赖注入的容器。
原文地址http://fabien.potencier.org/article/11/what-is-dependency-injection
另外有需要云服务器可以了解下创新互联cdcxhl.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
售后响应及时
7×24小时客服热线数据备份
更安全、更高效、更稳定价格公道精准
项目经理精准报价不弄虚作假合作无风险
重合同讲信誉,无效全额退款