0

0

理解PHP依赖注入容器系列(一) 什么是

黄舟

黄舟

发布时间:2016-12-28 10:22:01

|

2088人浏览过

|

来源于php中文网

原创

本文是php依赖注入容器的实现这个系列的第一章。 
今天,先不谈容器(container),首先用一些具体的例子来介绍依赖注入的概念,证明依赖注入这种模式可以解决哪些问题,同时能给开发人员带来哪些好处。 
如果你已经知道了依赖注入的概念,你可以跳过这篇文章。

依赖注入可能是我所知道的最简单设计模式之一,很多情况下可能你无意识中已经使用了依赖注入。不过它也是最难解释的一个。我认为有一部分原因是由于大多数介绍依赖注入的例子缺乏实际意义,让人难理解。因为PHP主要用于Web开发,那就先来看一个简单的web开发实例。

HTTP本身是一个无状态的连接协议,为了支持客户在发起WEB请求时应用程序能存储用户信息,我们就需要通过一种技术来实现存储状态交互。理所当然最简单的是使用cookie,更好的方式是PHP内置的Session机制。

$_SESSION['language'] = 'fr';

上面代码将用户语言存储在了名为language的Session变量中,因此在该用户随后的请求中,可以通过全局数组$_SESSION来获取language:

$user_language = $_SESSION['language'];

依赖注入主要用于面向对像开发,现在让我们假设我们有一个SessionStorage类,该类封装了PHP Session机制:

立即学习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];
  }
  // ...
}

同时还有一个User类提供了更高级的封装:

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();

一切都很美好,除非你的程序需要更好的扩展性。假设现在你想要更改保存session_id的COOKIE键值,以下有一些可供选择的方法:

User类中创建SessionStorage实例时,在SessionStorage构造方法中使用字符串’SESSION_ID’硬编码:

class User
{
    function __construct()
    {
        $this->storage = new SessionStorage('SESSION_ID');
    }
    // ...
}

在User类外部设置一个常量(名为STORAGE_SESSION_NAME)

class User
{
  function __construct()
  {
    $this->storage = new SessionStorage(STORAGE_SESSION_NAME);
  }
  // ...
}
define('STORAGE_SESSION_NAME', 'SESSION_ID');

通过User类构造函数中的参数传递Session name

class User
{
  function __construct($sessionName)
  {
    $this->storage = new SessionStorage($sessionName);
  }
  // ...
}
$user = new User('SESSION_ID');

还是通过User类构造函数中的参数传递Session name,不过这次参数采用数组的方式

class User
{
  function __construct($storageOptions)
  {
    $this->storage = new SessionStorage($storageOptions['session_name']);
  }
  // ...
}
$user = new User(array('session_name' => 'SESSION_ID'));

上面的方式都很糟糕。 
在user类中硬编码设置session name的做法没有真正解决问题,如果以后你还需要更改保存session_id的COOKIE键值,你不得不再一次修改user类(User类不应该关心COOKIE键值)。 
使用常量的方式同样很糟,造成User类依赖于一个常量设置。 
通过User类构造函数的参数或数组来传递session name相对来说好一些,不过也不完美,这样做干扰了User类构造函数的参数,因为如何存储Session并不是User类需要关心的,User类不应该和它们扯上关联。

通义千问
通义千问

阿里巴巴推出的全能AI助手

下载

另外,还有一个问题不太好解决:我们如何改变SessionStorage类。这种应用场景很多,比如你要用一个Session模拟类来做测试,或者你要将Session存储在数据库或者内存中。目前这种实现方式,在不改变User类的情况下,很难做到这点。

现在,让我们来使用依赖注入。回忆一下,之前我们是在User类内部创建SessionStorage对像的,现在我们修改一下,让SessionStorage对像通过User类的构造函数传递进去。

class User
{
  function __construct($storage)
  {
    $this->storage = $storage;
  }
  // ...
}

这就是依赖注入最经典的案例,没有之一。现在使用User类有一些小小的改变,首先你需要创建SessionStorage对像。

$storage = new SessionStorage('SESSION_ID');
$user = new User($storage);

现在,配置session存储对像很简单了,同样如果改变session存储对像也很简单,所有这一切并不需要去更新User类,降低了业务类之间的耦合。 
Pico Container 的网站上是这样描述依赖注入:

依赖注入是通过类的构造函数、方法、或者直接写入的方式,将所依赖的组件传递给类的方式。

所以依赖注入并不只限于通过构造函数注入。下面来看看几种注入方式:

构造函数注入

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: 构造函数注入的例子
$dispatcher = new sfEventDispatcher();
$storage = new sfMySQLSessionStorage(array('database' => 'session', 'db_table' => 'session'));
$user = new sfUser($dispatcher, $storage, array('default_culture' => 'en'));
// Zend Framework: setter方式注入的例子
$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);

 以上就是理解PHP依赖注入容器系列(一) 什么是的内容,更多相关内容请关注PHP中文网(www.php.cn)!

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

10

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

29

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

21

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

21

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

13

2026.01.22

PHP特殊符号教程合集
PHP特殊符号教程合集

本专题整合了PHP特殊符号相关处理方法,阅读专题下面的文章了解更多详细内容。

11

2026.01.22

PHP探针相关教程合集
PHP探针相关教程合集

本专题整合了PHP探针相关教程,阅读专题下面的文章了解更多详细内容。

8

2026.01.22

菜鸟裹裹入口以及教程汇总
菜鸟裹裹入口以及教程汇总

本专题整合了菜鸟裹裹入口地址及教程分享,阅读专题下面的文章了解更多详细内容。

55

2026.01.22

Golang 性能分析与pprof调优实战
Golang 性能分析与pprof调优实战

本专题系统讲解 Golang 应用的性能分析与调优方法,重点覆盖 pprof 的使用方式,包括 CPU、内存、阻塞与 goroutine 分析,火焰图解读,常见性能瓶颈定位思路,以及在真实项目中进行针对性优化的实践技巧。通过案例讲解,帮助开发者掌握 用数据驱动的方式持续提升 Go 程序性能与稳定性。

9

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 9.2万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 10.1万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号