PHP解耦的三重境界(浅谈服务容器)


Posted in PHP onMarch 13, 2017

阅读本文之前你需要掌握:PHP语法,面向对象

在完成整个软件项目开发的过程中,有时需要多人合作,有时也可以自己独立完成,不管是哪一种,随着代码量上升,写着写着就“失控”了,渐渐“丑陋接口,肮脏实现”,项目维护成本和难度上升,到了难以维持的程度,只有重构或者重新开发。

第一重境界

假设场景:我们需要写一个处理类,能够同时操作会话,数据库和文件系统。我们或许会这么写。

境界特征:可以运行,但是严重耦合

class DB{
 public function DB($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class FileSystem{
 public function FileSystem($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class Session{
 public function Session($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class Writer{
 public function Write(){
 $db=new DB(1,2);
 $filesystem=new FileSystem(3,4);
 $session=new Session(5,6);
 }
}
$writer=new Writer();
$writer->write();

写法缺点:

1.在公有函数中构造对象,一旦涉及到如数据库参数的变动,修改会有很大的工作量

2.负责设计Writer类的人员需要对DB等类的各种API要熟悉

有没有办法降低耦合度?

第二重境界(参数依赖)

假设场景:数据库地址因为客户不同,需要经常更换,调用到DB的类很多(假如有几十个),希望即使更改了数据库地址,也不用去修改这些类的代码。

class DB{
 public function DB($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class FileSystem{
 public function FileSystem($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class Session{
 public function Session($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class Writer{
 protected $_db;
 protected $_filesystem;
 protected $_session;
 public function Set($db,$filesystem,$session){
 $this->_db=$db;
 $this->_filesystem=$filesystem;
 $this->_session=$session;
 }
 public function Write(){

 }
}
$db=new DB(1,2);
$filesystem=new FileSystem(3,4);
$session=new Session(5,6);
$writer=new Writer();
$writer->Set($db,$filesystem,$session);
$writer->write();

虽然把DB类的构造移到了客户端,一旦涉及修改,工作量大大降低,但是新问题来了:为了创建一个Writer类,我们需要先创建好DB类,FileSystem类等,这对负责涉及Writer类的人来说,要求是很高的,他需要看很多其他类文档,一个个创建(可能还需要初始化),然后才能创建出他要的writer变量。

所以,我们希望,能有一种更好的写法,使得写Writer类的人,用一种更加快捷的接口,就能创建和调用他要的类,甚至连参数都不用填。

第三重境界(IOC容器)

经过前两重境界,我们希望能新增以下这些好处:

1.希望DB类,Session类,FileSystem类“拿来即用”,不用每次繁琐的初始化,比如写$db=new DB(arg1,arg2);这类语句。

2.希望DB等类型的对象是“全局”,在整个程序运行期间,随时可以调用。

3.调用DB等类型的程序员不用知道这个类太多的细节,甚至可以用一个字符串的别名来创建这样一个对象。

能够实现以上目标的就是IOC容器,可以把IOC容器简单的看成一个全局变量,并用关联数组把字符串和构造函数做绑定。

我们先实现一个容器类

class Container{
 public $bindings;
 public function bind($abstract,$concrete){
 $this->bindings[$abstract]=$concrete;
 }
 public function make($abstract,$parameters=[]){
 return call_user_func_array($this->bindings[$abstract],$parameters);
 }
}

服务注册(绑定)

$container=new Container();
$container->bind('db',function($arg1,$arg2){
 return new DB($arg1,$arg2);
});
$container->bind('session',function($arg1,$arg2){
 return new Session($arg1,$arg2);
});
$container->bind('fs',function($arg1,$arg2){
 return new FileSystem($arg1,$arg2);
});

容器依赖

class Writer{
 protected $_db;
 protected $_filesystem;
 protected $_session;
 protected $container;
 public function Writer(Container $container){
 $this->_db=$container->make('db',[1,2]);
 $this->_filesystem=$container->make('session',[3,4]);
 $this->_session=$container->make('fs',[5,6]);
 }
}
$writer=new Writer($container);

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

PHP 相关文章推荐
php下利用curl判断远程文件是否存在的实现代码
Oct 08 PHP
CI框架开发新浪微博登录接口源码完整版
May 28 PHP
PHP中使用localhost连接Mysql不成功的解决方法
Aug 20 PHP
php修改指定文件后缀的方法
Sep 11 PHP
简单实用的PHP防注入类实例
Dec 05 PHP
yii使用activeFileField控件实现上传文件与图片的方法
Dec 28 PHP
php实现word转html的方法
Jan 22 PHP
php调用自己java程序的方法详解
May 13 PHP
php reset() 函数指针指向数组中的第一个元素并输出实例代码
Nov 21 PHP
PHP中str_split()函数的用法讲解
Apr 11 PHP
thinkphp整合系列之极验滑动验证码geetest功能
Jun 18 PHP
Laravel 实现添加多语言提示信息
Oct 25 PHP
PHP控制反转(IOC)和依赖注入(DI)
Mar 13 #PHP
ThinkPHP中类的构造函数_construct()与_initialize()的区别详解
Mar 13 #PHP
Thinkphp结合ajaxFileUpload实现异步图片传输示例
Mar 13 #PHP
php解析mht文件转换成html的实例
Mar 13 #PHP
使用phpQuery获取数组的实例
Mar 13 #PHP
php获取linux命令结果的实例
Mar 13 #PHP
老生常谈PHP位运算的用途
Mar 12 #PHP
You might like
PHP下通过file_get_contents的代理使用方法
2011/02/16 PHP
PHP列出MySQL中所有数据库的方法
2015/03/12 PHP
PHP用户注册邮件激活账户的实现代码
2017/05/31 PHP
基于PHP实现短信验证码发送次数限制
2020/07/11 PHP
jquery.tmpl JQuery模板插件
2011/10/10 Javascript
script不刷新页面的联动前后代码
2013/09/18 Javascript
弹出窗口并且此窗口带有半透明的遮罩层效果
2014/03/13 Javascript
js简单的弹出框有关闭按钮
2014/05/05 Javascript
js用拖动滑块来控制图片大小的方法
2015/02/27 Javascript
javasript实现密码的隐藏与显示
2015/05/08 Javascript
AngularJS教程之环境设置
2016/08/16 Javascript
原生js编写焦点图效果
2016/12/08 Javascript
Vue.js常用指令的使用小结
2017/06/23 Javascript
webpack学习笔记之优化缓存、合并、懒加载
2017/08/24 Javascript
vue的style绑定background-image的方式和其他变量数据的区别详解
2018/09/03 Javascript
layui table单元格事件修改值的方法
2019/09/24 Javascript
js实现坦克移动小游戏
2019/10/28 Javascript
原生js实现贪吃蛇游戏
2020/10/26 Javascript
[38:21]2014 DOTA2国际邀请赛中国区预选赛5.21 TongFu VS LGD-CDEC
2014/05/22 DOTA
[04:04]显微镜下的DOTA2第六期——电影级别的华丽团战
2014/06/20 DOTA
python简单实现旋转图片的方法
2015/05/30 Python
python+requests+unittest API接口测试实例(详解)
2017/06/10 Python
解决Python中list里的中文输出到html模板里的问题
2018/12/17 Python
python常用函数与用法示例
2019/07/02 Python
python中的TCP(传输控制协议)用法实例分析
2019/11/15 Python
python+selenium 脚本实现每天自动登记的思路详解
2020/03/11 Python
详解基于Scrapy的IP代理池搭建
2020/09/29 Python
canvas实现二维码和图片合成的示例代码
2018/08/01 HTML / CSS
365 Tickets英国:全球景点门票
2019/07/06 全球购物
解决方案设计综合面试题
2015/08/31 面试题
投标单位介绍信
2014/01/09 职场文书
社区活动邀请函范文
2014/01/29 职场文书
主要负责人任命书
2014/06/06 职场文书
学校个人对照检查材料
2014/08/26 职场文书
出售房屋委托书范本
2014/09/24 职场文书
大学学生会主席竞选稿
2015/11/19 职场文书