依赖注入
简介:Dependency Injection 依赖注入
EasySwoole实现了简单版的IOC,使用 IOC 容器可以很方便的存储/获取资源,实现解耦。
使用依赖注入,最重要的一点好处就是有效的分离了对象和它所需要的外部资源,使得它们松散耦合,有利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
在我们的日常开发中,创建对象的操作随处可见以至于对其十分熟悉的同时又感觉十分繁琐,每次需要对象都需要亲手将其new出来,甚至某些情况下由于坏编程习惯还会造成对象无法被回收,这是相当糟糕的。但更为严重的是,我们一直倡导的松耦合,少***原则,这种情况下变得一无是处。于是前辈们开始谋求改变这种编程陋习,考虑如何使用编码更加解耦合,由此而来的解决方案是面向接口的编程。
--摘自《searswoole开发文档》
本文将解析并实现下列功能。
- 1、singleton模式的巧妙实现。
- 2、通过Di方式实现简单的容器,方便存取资源,从而达到解耦的目的。
代码实现
文件结构
- \client.php 功能调用入口
- \AbstractInterface\Singleton.php 单例抽象接口
- \Lib\Redis.php redis服务类
- \Service\Di.php 依赖注入实现简单Ioc容器
单例实现过程解读
client.php
namespace App;
//定义项目根目录
define('APP_ROOT', dirname(__FILE__));
use Exception;
use Yaconf;
require_once APP_ROOT . '/Lib/Redis.php';
require_once APP_ROOT . '/Service/Di.php';
use App\Lib\Redis;
//通过Yaconf扩展高效获取配置信息
if (!Yaconf::has('easyswoole_api')) throw new Exception('项目配置ini文件不存在');
$redisConfig = Yaconf::get('easyswoole_api')['redis'] ?? [];
if (empty($redisConfig)) throw new Exception('项目redis配置不存在');
$config = [
'host' => (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');
\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);
}
}