热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入解析PHP容器概念:理解依赖注入容器的基础与应用(第一篇)

本文作为探讨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机制: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 nameclass 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类不应该和它们扯上关联。

另外,还有一个问题不太好解决:我们如何改变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中文网,转载请注明出处,感谢您的尊重!



推荐阅读
  • Spring Boot 中静态资源映射详解
    本文深入探讨了 Spring Boot 如何简化 Web 应用中的静态资源管理,包括默认的静态资源映射规则、WebJars 的使用以及静态首页的处理方法。通过本文,您将了解如何高效地管理和引用静态资源。 ... [详细]
  • EasyMock实战指南
    本文介绍了如何使用EasyMock进行单元测试,特别是当测试对象的合作者依赖于外部资源或尚未实现时。通过具体的示例,展示了EasyMock在模拟对象行为方面的强大功能。 ... [详细]
  • 利用Selenium与ChromeDriver实现豆瓣网页全屏截图
    本文介绍了一种使用Selenium和ChromeDriver结合Python代码,轻松实现对豆瓣网站进行完整页面截图的方法。该方法不仅简单易行,而且解决了新版Selenium不再支持PhantomJS的问题。 ... [详细]
  • 本文详细探讨了如何通过分析单个或多个线程在瓶颈情况下的表现,来了解处理器资源的消耗。无论是单进程还是多进程环境,监控关键指标如线程数量、占用时间及调度优先级等,有助于揭示潜在的性能问题。 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 在尝试使用C# Windows Forms客户端通过SignalR连接到ASP.NET服务器时,遇到了内部服务器错误(500)。本文将详细探讨问题的原因及解决方案。 ... [详细]
  • Python包管理工具pip的使用指南
    本文详细介绍了如何使用pip进行Python包的安装、管理和常见问题的解决方法,特别针对国内用户提供了优化建议。 ... [详细]
  • 本文探讨了一个特定于 Spring 4.2.5 的问题,即在应用上下文刷新事件(ContextRefreshedEvent)触发时,带有 @Transactional 注解的 Bean 未能正确代理事务。该问题在 Spring 4.1.9 版本中正常运行,但在升级至 4.2.5 后出现异常。 ... [详细]
  • Java EE CDI:解决依赖关系冲突的实例
    在本教程中,我们将探讨如何在Java EE的CDI(上下文和依赖注入)框架中有效解决依赖关系的冲突问题。通过学习如何使用限定符,您将能够为应用程序的不同客户端提供多种接口实现,并确保每个客户端都能正确调用其所需的实现。 ... [详细]
  • 主板IO用W83627THG,用VC如何取得CPU温度,系统温度,CPU风扇转速,VBat的电压. ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 掌握Spring MVC中自定义类型转换与格式化的技巧
    近期,在开发一款小程序的过程中遇到了几个Spring MVC接口需要传递时间参数的问题。本文将详细介绍如何利用Java 8 Time API在Spring MVC中实现时间参数的自定义类型转换和格式化。 ... [详细]
  • Flowable系列教程:运用ProcessEngineConfigurator实现高级流程引擎配置
    本文探讨了通过ProcessEngineConfigurator接口实现对Flowable流程引擎的高级配置方法。这种方法允许开发者通过自定义配置器来增强或修改流程引擎的行为。 ... [详细]
  • 本文通过探讨React中Context的使用,解决了在多层级组件间传递状态的难题。我们将详细介绍Context的工作原理,并通过实际案例演示其在项目中的具体应用。 ... [详细]
author-avatar
手机用户2502892503
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有