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中http_build_query 的一个问题
Mar 25 PHP
PHP中“简单工厂模式”实例代码讲解
Sep 04 PHP
浅析linux下apache服务器的配置和管理
Aug 10 PHP
PhpDocumentor 2安装以及生成API文档的方法
May 21 PHP
PHP中使用socket方式GET、POST数据实例
Apr 02 PHP
详解WordPress中用于合成数组的wp_parse_args()函数
Dec 18 PHP
CI配置多数据库访问的方法
Mar 28 PHP
什么是PHP文件?如何打开PHP文件?
Jun 27 PHP
PHP 实现人民币小写转换成大写的方法及大小写转换函数
Nov 17 PHP
Laravel框架分页实现方法分析
Jun 12 PHP
Laravel 模型关联基础教程详解
Sep 17 PHP
php 输出缓冲 Output Control用法实例详解
Mar 03 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设计模式 php实现享元模式(flyweight)
2015/12/07 PHP
PHP模板引擎Smarty中的保留变量用法分析
2016/04/11 PHP
php制作圆形用户头像的实例_自定义封装类源代码
2017/09/18 PHP
JavaScript 动态创建VML的方法
2009/10/14 Javascript
JavaScript 学习初步 入门教程
2010/03/25 Javascript
document.getElementById介绍
2011/09/13 Javascript
初识Node.js
2014/09/03 Javascript
jQuery+PHP+MySQL实现无限级联下拉框效果
2016/02/19 Javascript
用js实现简单算法的实例代码
2016/09/24 Javascript
js图片切换具体实现代码
2016/10/13 Javascript
正则表达式,替换所有HTML标签的简单实例
2016/11/28 Javascript
利用js判断手机是否安装某个app的多种方案
2017/02/13 Javascript
iview日期控件,双向绑定日期格式的方法
2018/03/15 Javascript
快速解决brew安装特定版本flow的问题
2018/05/17 Javascript
微信小程序实现滑动切换自定义页码的方法分析
2018/12/29 Javascript
JS实现的类似微信聊天效果示例
2019/01/29 Javascript
jQuery事件委托代码实践详解
2019/06/21 jQuery
浅谈Webpack4 Tree Shaking 终极优化指南
2019/11/18 Javascript
koa-passport实现本地验证的方法示例
2020/02/20 Javascript
vue3使用vue-count-to组件的实现
2020/12/25 Vue.js
Python实现的简单万年历例子分享
2014/04/25 Python
Python urls.py的三种配置写法实例详解
2017/04/28 Python
python函数式编程学习之yield表达式形式详解
2018/03/25 Python
Tensorflow中使用tfrecord方式读取数据的方法
2018/06/19 Python
Python3.4 splinter(模拟填写表单)使用方法
2018/10/13 Python
html5开发三八女王节表白神器
2018/03/07 HTML / CSS
中东奢侈品购物网站:Ounass
2020/09/02 全球购物
mysql的最长数据库名,表名,字段名可以是多长
2014/04/21 面试题
交通事故赔偿协议书
2014/04/15 职场文书
文明礼仪伴我行演讲稿
2014/05/12 职场文书
搞笑结婚保证书
2015/05/08 职场文书
关于运动会的广播稿
2015/08/19 职场文书
《假如》教学反思
2016/02/17 职场文书
创业项目(超低成本创业项目)
2019/08/16 职场文书
Golang 实现超大文件读取的两种方法
2021/04/27 Golang
win10滚动条自动往上跑怎么办?win10滚动条自动往上跑的解决方法
2022/08/05 数码科技