听 Fabien Potencier 谈Symfony2 之 《What is Dependency Injection ?》

 

什么是依赖注入?
从PHP实现角度来分析依赖注入,因为PHP主要用于web开发,所以我们就看Web应用例子。
为了克服HTTP协议的无状态性,web应用程序需要有一个途径来在web请求之间存储用户信息。最简单的方式是使用cookie或者采用更好一点的PHP内建的Session机制。

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

上面这句代码就实现了把语言存储到Session变量language里。从此之后,同一用户一些后续的请求都可以使用这个值了。因为$_SESSION 数组是个全局的变量。调用方式如下:

$user_language = $_SESSION['language'];

因为依赖注入是面向对象世界里的概念,现在我们需要把PHP Session机制封装到一个类里面,然后应用到web应用程序中。

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 = new User();
$user->setLanguage('en');
$user_language = $user->getLanguage();

如果做得更加灵活一点呢?你想改变会话cookie的名字怎么办?有几个方式:可以在User类中在SessionStorage的构造函数中指定,即一种硬编码方式。

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

一种方式是把Session名作为User 类构造函数的参数:

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

还有一种方式是PHP代码中常见的为Session存储类添加一个可选设置项数组options

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

实现的方法有很多啊,无论是硬编码,设置为常量,作为构造函数的参数还是可选项数组都不是最佳选择。虽然后两者看起来好那么一点点,但它让User类的构造器堆积了一些跟自己没关系的参数。

继续,另外一个问题又来了,如果我想改变SessionStorage类怎么办?比如在测试时,制造个假数据。或者你想把Session保存到数据库或者内存中时,就需要改变SessionStorage类了。就目前情况来看,如果不修改User类是不可能实现改变SessionStorage类的。

现在我们考虑依赖注入,我们不在User类中创建SessionStorage对象,而是在外部创建后作为User类的构造方法参数传递给User对象。

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

OK,这就是依赖注入,没别的了!现在再使用User类时可能需要比上次麻烦一点:

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

现在在不改变User类的前提下,改变Session名字,改变SessionStorage类,你想干啥都行了!

总结一下:依赖注入是组件们通过他们的构造器,方法,或者属性字段来获取他们依赖的对象。

构造器注入:

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

设置器注入(方法注入):

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

属性字段注入:

class User
{
public $sessionStorage;
} $user->sessionStorage = $storage;

这些在Symfony 中你都会看到他们的身影:

构造注入:

$dispatcher = new sfEventDispatcher();
$storage = new sfMySQLSessionStorage(array('database' => 'session', 'db_table' => 'session'));
$user = new sfUser($dispatcher, $storage, array('default_culture' => 'en'));

将$dispatcher对象和$storage对象注入到$user对象中。

方法注入:

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

该注入俗称为setter注入。

Ok,这就是依赖注入了,它会在Symfony2中发展到服务容器注入。 以提供更加方便灵活松散耦合的多级依赖管理。它就是Service Container,它为Symfony2的执行效率和可扩展性提供了最强大的支持。

听 Fabien Potencier 谈Symfony2 之 《What is Dependency Injection ?》的更多相关文章

  1. 听 Fabien Potencier 谈Symfony2 之 《What is Symfony2 ?》

    Symfoy2 是什么? PHP世界里又一广受关注的web MVC框架? Fabien Potencier 却不这么说! Fabien Potencier这样定义Symfoy2 是个什么东西: 首先, ...

  2. 有容云:上车 | 听老司机谈Docker安全合规建设

    编者注: 本文根据7月19日DockOne社群分享内容整理而成,分享嘉宾蒋运龙,有容云高级咨询顾问,一个IT的老兵,十年来混迹于存储.三网融合.多屏互动.智能穿戴.第三方支付.Docker等行业:经历 ...

  3. 依赖注入(DI)与服务容器(IoC)

    参考文章:http://www.yuansir-web.com/2014/03/20/%E7%90%86%E8%A7%A3php-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A ...

  4. Symfony2 是什么(转)

    本文转自:http://www.cnblogs.com/Seekr/archive/2012/06/15/2550894.html Symfoy2 是什么? PHP世界里又一广受关注的web MVC框 ...

  5. 深入浅出Symfony2 - 如何提高网站响应速度 [转]

    简介 Symfony2是一个基于PHP语言的Web开发框架,有着开发速度快.性能高等特点.但Symfony2的学习曲线也比较陡峭,没有经验的初学者往往需要一些练习才能掌握其特性.相对其他框架,Symf ...

  6. Symfony2 学习笔记之内部构件

    Symfony2内部是怎样工作的以及我们如何来扩展它呢?从外部整体上看,symfony2代码是由许多独立的层构成,每一层都是建立在前一层基础之上.其中,自动加载时不受框架直接管理的,它完全是在Univ ...

  7. 浅谈C#依赖注入

    什么是依赖注入?不管是js中的一些前端框架还是,java,C#,php等中的一些后端开发框架中,都会涉及这个看着逼格略高的词语:依赖注入,越是看着好像很厉害的东西越是会让许多人学习产生恐惧,好像很厉害 ...

  8. Swift语言精要 - 浅谈代理模式(Delegate)

    在iOS编程中,我们经常谈到代理代理,也就是delegate,那么什么是代理呢? 我们来看一下cocoa对它的描述: Delegation is Cocoa’s term for passing of ...

  9. 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生

    [转].NET(C#):浅谈程序集清单资源和RESX资源   目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...

随机推荐

  1. 如何将文章列表用<li>分两列显示

    我们平时用ul或ol标签来罗列文章列表时默认是一列,为了美观起见,想把它们两列显示要如何操作呢?怎么用css定义它们? 其实相对比较简单,用几行css样式定义一下就够了,可以用div + css来控制 ...

  2. 如何用python发邮件

    python发送各类邮件的主要方法 一.相关模块介绍 发送邮件主要用到了smtplib和email两个模块,这里首先就两个模块进行一下简单的介绍:     1.smtplib模块 smtplib.SM ...

  3. what's the 爬虫之基本原理

    what's the 爬虫? 了解爬虫之前,我们首先要知道什么是互联网 1.什么是互联网? 互联网是由网络设备(网线,路由器,交换机,防火墙等等)和一台台计算机连接而成,总体上像一张网一样. 2.互联 ...

  4. 开发uniapp必备

    开发工具http://quickapp.dcloud.io/ 开发手册 http://uniapp.dcloud.io/api/README(2018-7-27 发布) 调试环境http://ask. ...

  5. Nginx Log日志统计分析常用命令

    IP相关统计 统计IP访问量(独立ip访问数量) awk '{print $1}' access.log | sort -n | uniq | wc -l 查看某一时间段的IP访问量(4-5点) gr ...

  6. Scala数据类型的继承结构

    Scala中,所有的值都是类对象,而所有的类,包括值类型,都最终继承自一个统一的根类型Any.统一类型,是Scala的又一大特点.更特别的是,Scala中还定义了几个底层类(Bottom Class) ...

  7. [py]环境变量的获取os.environ.get和设置

    $ export name='maotai' $ python >>> import os >>> os.environ.get('name', "&qu ...

  8. vue作用域 this

    设计到异步 function 回调的.this指向 需要用内部代替this 如果是箭头符号写法 就不需要 this永远是当前vue实例

  9. JS 8-4 OOP instanceof

    instanceof数据类型的判断方法 一般要求左边是个对象,右边是个函数或者构造器 [1,2] instanceof Array //true 左边的原型 指向了 右边的prototype属性

  10. Centos ssh 限制ip访问

    要确定客户端计算机是否允许连接到服务,TCP包装器将引用以下两个文件,这两个文件通常称为主机访问文件: /etc/hosts.allow /etc/hosts.deny 当TCP包裹服务接收到客户端请 ...