博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅析easyswoole源码Di原理与实现
阅读量:5866 次
发布时间:2019-06-19

本文共 5197 字,大约阅读时间需要 17 分钟。

依赖注入

  简介:Dependency Injection 依赖注入

  EasySwoole实现了简单版的IOC,使用 IOC 容器可以很方便的存储/获取资源,实现解耦。

  使用依赖注入,最重要的一点好处就是有效的分离了对象和它所需要的外部资源,使得它们松散耦合,有利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

  在我们的日常开发中,创建对象的操作随处可见以至于对其十分熟悉的同时又感觉十分繁琐,每次需要对象都需要亲手将其new出来,甚至某些情况下由于坏编程习惯还会造成对象无法被回收,这是相当糟糕的。但更为严重的是,我们一直倡导的松耦合,少***原则,这种情况下变得一无是处。于是前辈们开始谋求改变这种编程陋习,考虑如何使用编码更加解耦合,由此而来的解决方案是面向接口的编程。

  --摘自《easyswoole开发文档》

本文将解析并实现下列功能。

  • 1、singleton模式的巧妙实现。
  • 2、通过Di方式实现简单的容器,方便存取资源,从而达到解耦的目的。

代码实现

文件结构

浅析easyswoole源码Di原理与实现

  • \client.php 功能调用入口
  • \AbstractInterface\Singleton.php 单例抽象接口
  • \Lib\Redis.php   redis服务类
  • \Service\Di.php   依赖注入实现简单Ioc容器
单例实现过程解读

client.php

(string)$redisConfig['host'] ?? '', 'port' => (int)$redisConfig['port'] ?? '', 'timeout' => (string)$redisConfig['timeout'] ?? '', 'password' => (string)$redisConfig['password'] ?? '', 'database' => (int)$redisConfig['database'] ?? '', ]; //直接访问 //Redis::getInstance($config)->set('hello', 'world'); //echo Redis::getInstance($config)->get('hello'); //Di::getInstance()->clear(); //注入容器 //--方法一、注入实例 //Di::getInstance()->set('redis', \App\Lib\Redis::getInstance($config)); //--方法二、容器内部实例化(支持单例模式) Di::getInstance()->set('redis', \App\Lib\Redis::class, $config); //通过容器获取实例 $redisInstance = Di::getInstance()->get('redis'); $redisInstance->set('dear', 'hui'); echo $redisInstance->get('hello') . PHP_EOL; echo $redisInstance->get('dear') . PHP_EOL;} catch (\Exception $e) { //throw $e; echo $e->getMessage();}

\AbstractInterface\Singleton.php 单例抽象接口

namespace App\AbstractInterface;#声明为特性Trait Singleton{    private static $instance;    public static function getInstance(...$args)    {        if(!isset(self::$instance)){            //通过static静态绑定来new绑定的对象            self::$instance=new static(...$args);        }        return self::$instance;    }}

\Lib\Redis.php   redis服务类

namespace App\Lib;require_once APP_ROOT . '/AbstractInterface/Singleton.php';use App\AbstractInterface\Singleton;class Redis{        //这里通过使用特性来扩展Redis类的能力        //借助Singleton中的getInstance来new本类,创建redis连接实例        //Redis::getInstance(...)    use Singleton;    private $connectInstance = null;    /**     * Redis constructor.     * @param array $redisConfig     * @throws \Exception     */    private function __construct(array $redisConfig)    {        try {            //通过yaconf读取配置ini            if (!extension_loaded('redis')) throw new \Exception('Redis extension is not install');            $this->connectInstance = new \Redis();            $result = $this->connectInstance->connect($redisConfig['host'], $redisConfig['port'], $redisConfig['timeout']);            $this->connectInstance->auth($redisConfig['password']);            $this->connectInstance->select($redisConfig['database']);            if ($result === false) throw new \Exception('Connect redis server fail');        } catch (\Exception $e) {            throw $e;        }    }    public function __call($name, $arguments)    {        return $this->connectInstance->$name(...$arguments);    }}

Redis类引入Singleton特性,轻松实现单例子。

//通过Redis::getInstance就能获取实例

Redis::getInstance($config)->set('hello', 'world');
echo Redis::getInstance($config)->get('hello');

依赖注入的实现

\Service\Di.php   依赖注入实现简单Ioc容器

container[$key] = [ 'obj' => $obj, 'params' => $arg ]; } public function get(string $key) { if (!isset($this->container[$key])) return null; $result = $this->container[$key]; if (is_object($result['obj'])) { return $result['obj']; } elseif (is_callable($result['obj'])) {// 检测参数是否为合法的可调用结构(function,class method) return $result['obj']; } elseif (is_string($result['obj']) && class_exists($result['obj'])) { //通过反射方式获取实例化对象 $reflection = new \ReflectionClass($result['obj']); $constructor = $reflection->getConstructor(); $instance = null; if ($constructor->isPublic()) {//直接实例化 $instance = $reflection->newInstanceArgs($result['params']); } elseif ($constructor->isPrivate()) {//支持单例模式 if ($reflection->hasMethod('getInstance')) { $instance = $result['obj']::getInstance($result['params']); } } $this->container[$key]['obj'] = $instance; return $instance; } else { return $result['obj']; } } public function clear(): void { $this->container = []; } public function delete($key): void { unset($this->container[$key]); }}

在client.php中使用Di的使用

//向容器中注入实例

//Di::getInstance()->set('redis', \App\Lib\Redis::getInstance($config));
Di::getInstance()->set('redis', \App\Lib\Redis::class, $config);

//通过容器获取实例

$redisInstance = Di::getInstance()->get('redis');

$redisInstance->set('dear', 'hui');

echo $redisInstance->get('hello') . PHP_EOL;
echo $redisInstance->get('dear') . PHP_EOL;

总结

本案例涉及知识点:

1.通过Yaconf扩展高效获取配置信息
2.static静态绑定、trait特性
3.singleton模式的实现
4.Di依赖注入

附:Yaconf配置文件(easyswoole_api.ini)格式

redis.host = '192.168.1.99'

redis.port = 6379
redis.password = 'helloworld'
redis.database = 12
redis.timeout = 3

转载于:https://blog.51cto.com/phpme/2342625

你可能感兴趣的文章
codeigniter nginx rewrite规则配置【转】
查看>>
查找对应属性数量
查看>>
EOS开发语言和石墨烯技术介绍
查看>>
Hibernate--------八大类HQL查询集合
查看>>
robotframwork的WEB功能测试(二)—登录
查看>>
12.28jQuery 的取值赋值
查看>>
C++回调:利用Sink
查看>>
各种sqlite管理工具
查看>>
切片练习
查看>>
退信原因分析及解决办法
查看>>
项目: Zabbix监控搭建部署
查看>>
华为2016编程题
查看>>
APMServ 5.2.6.Apache启动失败,请检查相关配置。2.MySQL5.1启动失败的解决方法
查看>>
extJs学习基础4 Ext.each的用法
查看>>
Linux分区
查看>>
(转)IntelliJ IDEA java项目导入jar包,打jar包
查看>>
软件质量与测试--第六周作业 软件测试和评估
查看>>
实验4 颜色、字符串资源的使用
查看>>
Windows7配置python环境变量
查看>>
POJ 1654 Area 多边形面积 G++会WA
查看>>