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 相关文章推荐
简单实现限定phpmyadmin访问ip的方法
Mar 05 PHP
解析PHP缓存函数的使用说明
May 10 PHP
探讨php中遍历二维数组的几种方法详解
Jun 08 PHP
PHP include任意文件或URL介绍
Apr 29 PHP
ThinkPHP多语言支持与多模板支持概述
Aug 22 PHP
phpstorm编辑器乱码问题解决
Dec 01 PHP
php修改文件上传限制方法汇总
Apr 07 PHP
PHP实现linux命令tail -f
Feb 22 PHP
利用php抓取蜘蛛爬虫痕迹的示例代码
Sep 30 PHP
PHP合并数组函数array_merge用法分析
Feb 17 PHP
详解laravel passport OAuth2.0的4种模式
Nov 04 PHP
php 多进程编程父进程的阻塞与非阻塞实例分析
Feb 22 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
一个ORACLE分页程序,挺实用的.
2006/10/09 PHP
source.php查看源文件
2006/12/09 PHP
PHP array 的加法操作代码
2010/07/24 PHP
PHP中文编码小技巧
2014/12/25 PHP
PHP删除指定目录中的所有目录及文件的方法
2015/02/26 PHP
PHP YII框架开发小技巧之模型(models)中rules自定义验证规则
2015/11/16 PHP
学习php设计模式 php实现享元模式(flyweight)
2015/12/07 PHP
[原创]来自ImageSee官方 JavaScript图片浏览器
2008/01/16 Javascript
ExtJS 2.0 GridPanel基本表格简明教程
2010/05/25 Javascript
本地对象Array的原型扩展实现代码
2010/12/04 Javascript
js中判断用户输入的值是否为空的简单实例
2013/12/23 Javascript
Javascript基础教程之while语句
2015/01/18 Javascript
基于ajax实现文件上传并显示进度条
2015/08/03 Javascript
javascript实现去除HTML标签的方法
2016/12/26 Javascript
canvas实现图片根据滑块放大缩小效果
2017/02/24 Javascript
Angular1.x自定义指令实例详解
2017/03/01 Javascript
对vue中v-if的常见使用方法详解
2018/09/28 Javascript
BootStrap模态框闪退问题实例代码详解
2018/12/10 Javascript
vue proxy 的优势与使用场景实现
2020/06/15 Javascript
[44:43]完美世界DOTA2联赛决赛日 FTD vs GXR 第一场 11.08
2020/11/11 DOTA
[31:29]完美世界DOTA2联赛PWL S3 INK ICE vs Magma 第一场 12.20
2020/12/23 DOTA
使用python对excle和json互相转换的示例
2018/10/23 Python
python实现对象列表根据某个属性排序的方法详解
2019/06/11 Python
python 获取等间隔的数组实例
2019/07/04 Python
解决win7操作系统Python3.7.1安装后启动提示缺少.dll文件问题
2019/07/15 Python
python实现用类读取文件数据并计算矩形面积
2020/01/18 Python
python多进程 主进程和子进程间共享和不共享全局变量实例
2020/04/25 Python
澳大利亚最受欢迎的超级商场每日优惠:Catch
2020/11/17 全球购物
英国领先的在线鱼贩:The Fish Society
2020/08/12 全球购物
什么是测试驱动开发(TDD)
2012/02/15 面试题
带薪年假请假条
2014/02/04 职场文书
年度献血先进个人事迹材料
2014/02/14 职场文书
联片教研活动总结
2014/07/01 职场文书
画展邀请函
2015/01/31 职场文书
通知函格式范文
2015/04/27 职场文书
html输入两个数实现加减乘除功能
2021/07/01 HTML / CSS