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日历[测试通过]
Mar 27 PHP
QueryPath PHP 中的jQuery
Apr 11 PHP
PHP读取网页文件内容的实现代码(fopen,curl等)
Jun 23 PHP
pdo中使用参数化查询sql
Aug 11 PHP
解析PHP中VC6 X86和VC9 X86的区别及 Non Thread Safe的意思
Jun 28 PHP
php中通过curl检测页面是否被百度收录
Sep 27 PHP
Yii操作数据库的3种方法
Mar 11 PHP
php多功能图片处理类分享(php图片缩放类)
Mar 14 PHP
PHP抽奖算法程序代码分享
Oct 08 PHP
微信公众平台DEMO(PHP)
May 04 PHP
利用php-cli和任务计划实现订单同步功能的方法
May 03 PHP
PHP实现数据四舍五入的方法小结【4种方法】
Mar 27 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 isset()与empty()的使用区别详解
2010/08/29 PHP
记录PHP错误日志 display_errors与log_errors的区别
2012/10/09 PHP
php时区转换转换函数
2014/01/07 PHP
PHP获取MySql新增记录ID值的3种方法
2014/06/24 PHP
laravel 实现根据字段不同值做不同查询
2019/10/23 PHP
由JavaScript中call()方法引发的对面向对象继承机制call的思考
2011/09/12 Javascript
node.js中的fs.utimesSync方法使用说明
2014/12/15 Javascript
Jquery使用val方法读写value值
2015/05/18 Javascript
基于jQuery实现仿百度首页换肤背景图片切换代码
2015/08/25 Javascript
JavaScript中使用import 和require打包后实现原理分析
2018/03/07 Javascript
详解基于Vue cli生成的Vue项目的webpack4升级
2018/06/19 Javascript
ES6 async、await的基本使用方法示例
2020/06/06 Javascript
[01:11:27]2018DOTA2亚洲邀请赛小组赛 A组加赛 Newbee vs Optic
2018/04/03 DOTA
如何运行Python程序的方法
2013/04/21 Python
对Python+opencv将图片生成视频的实例详解
2019/01/08 Python
浅析Python语言自带的数据结构有哪些
2019/08/27 Python
Python列表去重复项的N种方法(实例代码)
2020/05/12 Python
python编写softmax函数、交叉熵函数实例
2020/06/11 Python
解决pytorch 数据类型报错的问题
2021/03/03 Python
canvas像素画板的实现代码
2018/11/21 HTML / CSS
adidas马来西亚官网:adidas MY
2020/09/12 全球购物
杭州联环马网络笔试题面试题
2013/08/04 面试题
Java语言程序设计测试题选择题部分
2014/04/03 面试题
怎样声明一个匿名的内部类
2016/06/01 面试题
人力资源管理专业应届生求职信
2013/09/28 职场文书
给交警的表扬信
2014/01/12 职场文书
幼儿园教师辞职信
2014/01/18 职场文书
安全检查与奖惩制度
2014/01/23 职场文书
小学生安全保证书
2014/02/01 职场文书
保护环境倡议书300字
2014/05/19 职场文书
工厂车间标语
2014/06/19 职场文书
幼儿园安全责任书范本
2014/07/24 职场文书
2014乡镇机关党员个人对照检查材料思想汇报
2014/10/09 职场文书
民事起诉状范文
2015/05/19 职场文书
公务员的复习计划书,请收下!
2019/07/15 职场文书
mysql通过group by分组取最大时间对应数据的两种有效方法
2022/09/23 MySQL