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下读取文本文件的代码
Jul 02 PHP
php设计模式 Observer(观察者模式)
Jun 26 PHP
PHP中的strtr函数使用介绍(str_replace)
Oct 20 PHP
php递归方法实现无限分类实例代码
Feb 28 PHP
windwos下使用php连接oracle数据库的过程分享
May 26 PHP
ThinkPHP空模块和空操作详解
Jun 30 PHP
php文件缓存类用法实例分析
Apr 22 PHP
PHP实现文件上传和多文件上传
Dec 24 PHP
Laravel模型间关系设置分表的方法示例
Apr 21 PHP
针对PHP开发安全问题的相关总结
Mar 22 PHP
PHP实现将上传图片自动缩放到指定分辨率,并保持清晰度封装类示例
Jun 17 PHP
Laravel向公共模板赋值方法总结
Jun 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
DC最新动画电影:《战争之子》为何内容偏激,毁了一个不错的漫画
2020/04/09 欧美动漫
UCenter Home二次开发指南
2009/05/28 PHP
ThinkPHP模板Switch标签用法示例
2014/06/30 PHP
关于laravel 日志写入失败问题汇总
2019/10/17 PHP
JQuery 风格的HTML文本转义
2009/07/01 Javascript
js数据验证集合、js email验证、js url验证、js长度验证、js数字验证等简单封装
2010/05/15 Javascript
jquery的extend和fn.extend的使用说明
2011/01/09 Javascript
省市区三级联动下拉框菜单javascript版
2015/08/11 Javascript
Jquery基础之事件操作详解
2016/06/14 Javascript
Vue 短信验证码组件开发详解
2017/02/14 Javascript
Angular.js实现动态加载组件详解
2017/05/28 Javascript
Angular.JS中指令ng-if的注意事项小结
2017/06/21 Javascript
基于js中document.cookie全面解析
2017/09/14 Javascript
jQuery实现获取table中鼠标click点击位置行号与列号的方法
2017/10/09 jQuery
js实现Tab选项卡切换效果
2020/07/17 Javascript
JavaScript实现左侧菜单效果
2017/12/14 Javascript
Angular中sweetalert弹框的基本使用教程
2018/07/22 Javascript
在angularJs中进行数据遍历的2种方法
2018/10/08 Javascript
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
2021/03/01 Vue.js
Python模拟浏览器上传文件脚本的方法(Multipart/form-data格式)
2018/10/22 Python
解决PyCharm不运行脚本,而是运行单元测试的问题
2019/01/17 Python
Python操作redis实例小结【String、Hash、List、Set等】
2019/05/16 Python
python IDLE 背景以及字体大小的修改方法
2019/07/12 Python
TensorFlow实现从txt文件读取数据
2020/02/05 Python
基于PyQT实现区分左键双击和单击
2020/05/19 Python
容易被忽略的Python内置类型
2020/09/03 Python
matplotlib交互式数据光标mpldatacursor的实现
2021/02/03 Python
用60行代码实现Python自动抢微信红包
2021/02/04 Python
加拿大折扣、优惠券和交易网站:WagJag
2018/02/07 全球购物
abstract是什么意思
2012/02/12 面试题
介绍一下Linux中的链接
2016/05/28 面试题
物业经理求职自我评价
2013/09/22 职场文书
运动会解说词100字
2014/01/31 职场文书
保护环境建议书100字
2014/05/13 职场文书
结婚司仪主持词
2015/06/29 职场文书
运动会跳远广播稿
2015/08/19 职场文书