談?wù)勱P(guān)于 DI(依賴注入)村生、IOC(容器)惊暴、AOP(切面編程)的設(shè)計(jì)模式
話不多說饼丘,直接上代碼
DI(依賴注入)
<?php
/**
* [DI - 依賴注入
* 原則:應(yīng)用的方法中不負(fù)責(zé)查找資源或者不負(fù)責(zé)查找其他依賴的協(xié)作對(duì)象, 而是通過參數(shù)趁桃,動(dòng)態(tài)的向該方法提供其他所需要的對(duì)象。DI 是IOC 的具體表現(xiàn)肄鸽,而IOC 不是一種設(shè)計(jì)模式而是一種思想
* ]
*
* @Author leeprince:2020-02-25 14:34
*/
class DB
{
public function select()
{
echo '查詢數(shù)據(jù)庫連接對(duì)象';
}
}
class User
{
protected $db;
public function __construct(DB $db)
{
$this->db = $db;
}
public function find()
{
$this->db->select();
}
}
$user = new User(new DB());
$user->find();
IOC(容器)
<?php
/**
* [Ioc - 控制反轉(zhuǎn) - 容器
* 概念:將設(shè)計(jì)好的對(duì)象及對(duì)象的依賴關(guān)系交給容器管理卫病,而不是傳統(tǒng)的直接在應(yīng)用組件內(nèi)部直接控制
* 步驟3:
* 1. 【綁定】定義接口和實(shí)現(xiàn)類,并將對(duì)象綁定到容器數(shù)組典徘,并返回可創(chuàng)建實(shí)例化對(duì)象的閉包函數(shù)
* 2. 【反射】在返回的閉包函數(shù)中蟀苛,根據(jù)反射機(jī)制(反射類)將要實(shí)例對(duì)象的構(gòu)造函數(shù)反射出來,并根據(jù)構(gòu)造函數(shù)是否包含參數(shù)返回實(shí)例對(duì)象
* 3. 【執(zhí)行】執(zhí)行閉包函數(shù)逮诲,通過反射類獲取實(shí)例對(duì)象
* ]
*
* @Author leeprince:2020-02-26 12:28
*/
define('IS_DEBUG', true);
/**
* [日志接口]
*
* @Author leeprince:2020-02-26 12:41
*/
interface iLog
{
public function write();
}
/**
* [實(shí)現(xiàn)文件日志]
*
* @Author leeprince:2020-02-26 12:41
*/
class FileLog implements iLog
{
public function write()
{
return '已記錄文件日志';
}
}
/**
* [實(shí)現(xiàn)數(shù)據(jù)庫日志]
*
* @Author leeprince:2020-02-26 12:41
*/
class DbLog implements iLog
{
public function write()
{
return '已記錄數(shù)據(jù)庫日志';
}
}
/**
* [根據(jù)依賴注入的實(shí)例來記錄日志]
*
* @Author leeprince:2020-02-26 12:47
*/
class Logger
{
protected $log;
public function __construct(iLog $log)
{
$this->log = $log;
}
public function index()
{
return $this->log->write();
}
}
/**
* [容器]
*
* @Author leeprince:2020-02-26 12:49
*/
class Ioc
{
protected $bindings = [];
/**
* [綁定到容器數(shù)組帜平,并返回可創(chuàng)建實(shí)例化對(duì)象的閉包函數(shù)]
* 可以繼續(xù)完善[已升級(jí)到bind 方法]:支持綁定閉包,進(jìn)行閉包判斷梅鹦,如果不是閉包則創(chuàng)建閉包裆甩,如果是則直接綁定
*
* @Author leeprince:2020-02-26 12:51
* @param $abstract 要綁定的抽象(標(biāo)識(shí)) / 接口名
* 【注意 :要綁定的到容器數(shù)組中的類或者接口名,使用「類型提示」 的方式在類的構(gòu)造函數(shù)中注入依賴項(xiàng)時(shí)齐唆,會(huì)根據(jù)構(gòu)造函數(shù)參數(shù)并反射后繼續(xù)實(shí)例化嗤栓,所以該值不可以隨便定義,否則報(bào)錯(cuò)箍邮。
* 所以建議該參數(shù)使用綁定的的類 / 接口名】
* @param $concrete 綁定的類名 / 接口的實(shí)現(xiàn)類名
*/
public function bindNoClosure($abstract, $concrete)
{
prt('[bind 方法]');
if (is_null($concrete)) {
$concrete = $abstract;
}
// 綁定閉包
$this->bindings[$abstract]['concrete'] = function ($ioc) use ($concrete) {
prt('bindings:'.$concrete);
return $ioc->build($concrete);
};
}
/**
* [綁定到容器數(shù)組茉帅,并返回可創(chuàng)建實(shí)例化對(duì)象的閉包函數(shù)]
*
* @Author leeprince:2020-03-08 15:34
* @Author leeprince:2020-02-26 12:51
* @param $abstract 要綁定的抽象(標(biāo)識(shí)) / 接口名
* @param $concrete 綁定的類名 / 接口的實(shí)現(xiàn)類名 / 閉包 / null(綁定自身)
*/
public function bind($abstract, $concrete = null)
{
prt('[bind 方法]');
if (is_null($concrete)) {
$concrete = $abstract;
}
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
// 綁定閉包
$this->bindings[$abstract]['concrete'] = $concrete;
}
/**
* [執(zhí)行閉包函數(shù),創(chuàng)建實(shí)例化對(duì)象]
*
* @Author leeprince:2020-02-26 13:05
* @param $abstract
* @return mixed
*/
public function make($abstract)
{
$ioc = $this->bindings[$abstract]['concrete'];
prt('[make]-$abstract:'.$abstract);
// prt(debug_backtrace());
return $ioc($this);
}
/**
* [獲取閉包函數(shù)]
*
* @Author leeprince:2020-03-09 23:01
* @param $abstract
* @param $concrete
* @return Closure
*/
public function getClosure($abstract, $concrete)
{
return function ($ioc, $parameters = []) use ($abstract, $concrete) {
return $ioc->build($concrete);
};
}
/**
* [通過反射類獲取實(shí)例(創(chuàng)建對(duì)象)]
*
* @Author leeprince:2020-02-26 12:57
* @param $concrete
*/
public function build($concrete)
{
// 使用反射類反射出當(dāng)前類的所有信息
$reflection = new ReflectionClass($concrete);
prt('[build]-$concrete:'.$concrete);
// 判斷是否可以實(shí)例化
if (!$reflection->isInstantiable()) {
throw new Exception('該類無法實(shí)例化', 1);
}
// 獲取構(gòu)造函數(shù)
$constructor = $reflection->getConstructor();
if (is_null($constructor)) {
// 實(shí)例化對(duì)象
return $reflection->newInstance();
} else {
// 獲取構(gòu)造函數(shù)的參數(shù)
$depenen = $constructor->getParameters();
$instences = $this->getDependencies($depenen);
return $reflection->newInstanceArgs($instences);
}
}
/**
* [根據(jù)構(gòu)造函數(shù)中的類型提示參數(shù)(依賴注入)中繼續(xù)實(shí)例化對(duì)象]
*
* @Author leeprince:2020-02-26 22:54
* @param array $depenen
* @return array
*/
protected function getDependencies(array $depenen)
{
$depenencies = [];
prt($depenen, '[getDependencies]-參數(shù)$depenen:');
foreach ($depenen as $parameter) {
prt($parameter->getClass(), '[getDependencies]-$parameter->getClass():');
prt($parameter->getClass()->name, '[getDependencies]-$parameter->getClass()->name:');
$depenencies[] = $this->make($parameter->getClass()->name);
}
prt($depenencies, '[getDependencies]-$depenencies:');
return $depenencies;
}
}
// 實(shí)例化容器
$ioc = new Ioc();
// 綁定自身
$ioc->bind('DbLog', 'DbLog');
$ioc->bind('FileLog', 'FileLog');
$log = $ioc->make('FileLog'); // // $log = $ioc->make('DbLog');
echo $log->write();
// 綁定閉包
$ioc->bind('DbLog', function($ioc) {
return new DbLog();
});
$log = $ioc->make('DbLog');
echo $log->write();
// 綁定接口到實(shí)現(xiàn)
$ioc->bind('iLog', 'DbLog'); // $ioc->bind('iLog', 'FileLog');
$ioc->bind('logger', 'Logger');
$logger = $ioc->make('logger');
echo $logger->index();
function prt($data, $msg = '')
{
if (!IS_DEBUG) {
echo '<pre>';
echo $msg;
print_r($data);
}
}
AOP(切面編程)
<?php
/**
* [AOP - 切面編程
* 把去要調(diào)用的重復(fù)代碼提前抽離出來锭弊,然后注入到需要的業(yè)務(wù)執(zhí)行里面
* ]
*
* @Author leeprince:2020-02-26 12:28
*/
/**
* [sesssion 緩存]
*
* @Author leeprince:2020-02-28 17:14
*/
class SessionCache
{
protected $name;
public function setName($name)
{
$this->name = $name;
}
/**
* [Description]
*
* @Author leeprince:2020-02-28 17:14
* @return mixed
*/
public function getName()
{
return $this->name;
}
}
/**
* [sesssion 緩存]
*
* @Author leeprince:2020-02-28 17:14
*/
class FileCache
{
protected $name;
public function setName($name)
{
$this->name = $name;
}
/**
* [Description]
*
* @Author leeprince:2020-02-28 17:14
* @return mixed
*/
public function getName()
{
return $this->name;
}
}
/**
* [AOP 切面緩存類]
*
* @Author leeprince:2020-02-28 17:17
*/
class Cache
{
protected $obj;
public function __construct($obj)
{
$this->obj = $obj;
}
public function __call($method, $args)
{
var_dump("method:{{$method}}--args:".json_encode($args));
return call_user_func_array([$this->obj, $method], $args);
}
}
$sessionCache = new Cache(new SessionCache());
$sessionCache->setName('leeprince');
var_dump($sessionCache->getName());
源碼地址
https://github.com/leeprince/my_pattern/tree/master/di_ioc_aop