当前位置:首页 » 编程语言 » php依赖注入

php依赖注入

发布时间: 2025-03-09 14:20:57

‘壹’ PHP Ding简介

Ding是一个轻量级的PHP框架,支持依赖注入、面向方面编程,并以MVC模式为基础,具有快速、简洁的特点。它提供了一系列功能,包括syslog、TCP套接字的非阻塞客户端和服务器端操作、定时器、自定义错误处理、信号与异常处理,以及对PAGI和PAMI的集成。这些特性使其在功能上与Java的Spring框架类似。

Ding框架注重简化开发过程,让开发者能够更高效地构建Web应用。依赖注入机制帮助开发者在运行时注入服务和组件,增强代码的可维护性和可测试性。面向方面编程(AOP)则允许开发者将横切关注点(如日志记录、事务管理)从核心业务逻辑中分离出来,以提高代码的清晰度和可重用性。

在性能方面,Ding实现了非阻塞I/O操作,利用syslog和TCP套接字技术提高网络通信效率,这对于实时应用和高并发场景尤为关键。定时器功能让开发者能够轻松实现任务的定时执行,满足各类定时需求。自定义错误处理机制增强了系统的健壮性,使错误处理更加灵活和针对性。信号与异常处理机制确保了程序在遇到异常情况时能够优雅地退出或进行适当的错误恢复。

Ding还提供了与PAGI和PAMI的集成,这为构建与语音或媒体相关的应用提供了便利。PAGI和PAMI是用于构建电话应用的API,Ding的集成使得开发者能够轻松地将这些功能融入到基于PHP的应用中。

综上所述,Ding框架通过提供丰富的功能集、高效的性能优化和灵活的编程模型,为PHP开发者提供了一种高效构建复杂应用的解决方案,类似于Java的Spring框架。

‘贰’ 怎样在PHP中更好的实现解耦

二、实现解耦两种方式
对于传统的PHP框架,我们很难把这个框架里某个需要的组件提取出来单独使用。因为这个组件可能会用到Logger对象、Config对象等等其他别的什么对象,而且这些外部依赖的代码是写死在源代码里的。有时候想单独使用框架内部的某个功能,不得不写大量的移植代码。要实现一个高度解耦的PHP框架,需要参考一下服务定位和依赖注入两种模式。在Zend framework2.0里,底层实现了DI,上层又按照SL封装了一个ServiceManager。

有人说Service Locator是一种反模式,因为在代码中使用Service Locator也算是一种隐含的外部依赖关系。其实这是矫情,难道在代码中使用IoC容器就不是外部依赖么?问题在于在恰当的场合使用恰当的模式。
首先要搞清楚代码究竟是属于“调用者”还是属于“被调用者”。作为“被调用者”,比如某个模块,可以预见到代码会被使用在不同场合,当然是对外部的耦合越小越好,对于自己所需要的外部接口,完全可以依赖外部“调用者”来被动注入;但对于的“调用者”代码来说,作为最终的应用层代码,需要做到统筹全局,当然是不可避免地要直接与各个组件产生耦合了。
至于什么时候用依赖注入,什么时候用服务定位,我个人的看法着这样的:编写组件时,最好使用依赖注入模式,特别是当这个组件可能被用于不同的项目工程中时;编写应用层代码、或者项目平台相关性强的组件时,可以使用服务定位模式。另外,依赖注入的外部接口对于组件来说应该是强依赖的,组件缺少这些外部接口是无法独立运行的;服务定位取得的外部接口应该是弱依赖的,在缺少接口的情况下,组件也能勉强运行。举个例子:用户模型组件在完成用户注册的过程中,会用到两个外部接口,一个是数据访问层接口,用于将用户信息保存到数据库或别的永久储存介质里,另一个是邮件发送接口,用于向用户邮箱发送一封注册确认信。其中数据访问层接口对于用户模型组件是强依赖关系,后者缺了前者将无法正常运行;而邮件发送接口对于用户模型组件是弱依赖关系,没有这个接口也能完成用户注册过程,只不过会产生一些警告信息。

‘叁’ PHP中什么是依赖注入

依赖注入可能是我所知道的最简单设计模式之一,很多情况下可能你无意识中已经使用了依赖注入。不过它也是最难解释的一个。我认为有一部分原因是由于大多数介绍依赖注入的例子缺乏实际意义,让人难理解。因为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 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类不应该和它们扯上关联。
另外,还有一个问题不太好解决:我们如何改变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);

热点内容
天正建筑编译菜单文件一直在加载 发布:2025-03-10 01:47:37 浏览:565
长安cx70自动挡有哪些配置 发布:2025-03-10 01:35:54 浏览:990
百洒存储 发布:2025-03-10 01:35:43 浏览:946
cf鬼跳脚本 发布:2025-03-10 01:33:34 浏览:177
python容错 发布:2025-03-10 01:19:53 浏览:264
android招聘郑州 发布:2025-03-10 01:06:37 浏览:110
手机问道脚本 发布:2025-03-10 01:06:37 浏览:167
网易大唐无双手游专业脚本 发布:2025-03-10 00:52:13 浏览:78
王者荣耀安卓qq区战区位置哪个最低 发布:2025-03-10 00:44:18 浏览:639
访问手机内部存储 发布:2025-03-10 00:35:10 浏览:847