溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

淺析easyswoole源碼Di原理與實(shí)現(xiàn)

發(fā)布時(shí)間:2020-07-29 22:23:56 來源:網(wǎng)絡(luò) 閱讀:2880 作者:hgditren 欄目:軟件技術(shù)

依賴注入

  簡(jiǎn)介:Dependency Injection 依賴注入

  EasySwoole實(shí)現(xiàn)了簡(jiǎn)單版的IOC,使用 IOC 容器可以很方便的存儲(chǔ)/獲取資源,實(shí)現(xiàn)解耦。

  使用依賴注入,最重要的一點(diǎn)好處就是有效的分離了對(duì)象和它所需要的外部資源,使得它們松散耦合,有利于功能復(fù)用,更重要的是使得程序的整個(gè)體系結(jié)構(gòu)變得非常靈活。

  在我們的日常開發(fā)中,創(chuàng)建對(duì)象的操作隨處可見以至于對(duì)其十分熟悉的同時(shí)又感覺十分繁瑣,每次需要對(duì)象都需要親手將其new出來,甚至某些情況下由于壞編程習(xí)慣還會(huì)造成對(duì)象無法被回收,這是相當(dāng)糟糕的。但更為嚴(yán)重的是,我們一直倡導(dǎo)的松耦合,少***原則,這種情況下變得一無是處。于是前輩們開始謀求改變這種編程陋習(xí),考慮如何使用編碼更加解耦合,由此而來的解決方案是面向接口的編程。

  --摘自《easyswoole開發(fā)文檔》

本文將解析并實(shí)現(xiàn)下列功能。
  • 1、singleton模式的巧妙實(shí)現(xiàn)。
  • 2、通過Di方式實(shí)現(xiàn)簡(jiǎn)單的容器,方便存取資源,從而達(dá)到解耦的目的。
代碼實(shí)現(xiàn)
文件結(jié)構(gòu)

淺析easyswoole源碼Di原理與實(shí)現(xiàn)

  • \client.php 功能調(diào)用入口
  • \AbstractInterface\Singleton.php 單例抽象接口
  • \Lib\Redis.php   redis服務(wù)類
  • \Service\Di.php   依賴注入實(shí)現(xiàn)簡(jiǎn)單Ioc容器
單例實(shí)現(xiàn)過程解讀

client.php

<?php
/**
 * Created by PhpStorm.
 * User: zrj
 * Date: 19-1-14
 * Time: 下午4:39
 */

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;
use App\Service\Di;

try {
    if (!Yaconf::has('easyswoole_api')) throw new Exception('項(xiàng)目配置ini文件不存在');
    $redisConfig = Yaconf::get('easyswoole_api')['redis'] ?? [];
    if (empty($redisConfig)) throw new Exception('項(xiàng)目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');

    //Di::getInstance()->clear();

    //注入容器

    //--方法一、注入實(shí)例
    //Di::getInstance()->set('redis', \App\Lib\Redis::getInstance($config));

    //--方法二、容器內(nèi)部實(shí)例化(支持單例模式)
    Di::getInstance()->set('redis', \App\Lib\Redis::class, $config);

    //通過容器獲取實(shí)例
    $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靜態(tài)綁定來new綁定的對(duì)象
            self::$instance=new static(...$args);
        }
        return self::$instance;
    }
}

\Lib\Redis.php   redis服務(wù)類

namespace App\Lib;

require_once APP_ROOT . '/AbstractInterface/Singleton.php';

use App\AbstractInterface\Singleton;

class Redis
{
        //這里通過使用特性來擴(kuò)展Redis類的能力
        //借助Singleton中的getInstance來new本類,創(chuàng)建redis連接實(shí)例
        //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特性,輕松實(shí)現(xiàn)單例子。

//通過Redis::getInstance就能獲取實(shí)例
Redis::getInstance($config)->set('hello', 'world');
echo Redis::getInstance($config)->get('hello');

依賴注入的實(shí)現(xiàn)

\Service\Di.php   依賴注入實(shí)現(xiàn)簡(jiǎn)單Ioc容器

 <?php
/**
 * Created by PhpStorm.
 * User: zrj
 * Date: 19-1-14
 * Time: 下午5:06
 */

namespace App\Service;

require_once APP_ROOT . '/AbstractInterface/Singleton.php';
require_once APP_ROOT . '/Lib/Redis.php';

use App\AbstractInterface\Singleton;

//use App\Lib\Redis;

class Di
{
    use Singleton;
    private $container = [];

    //注入容器
    public function set(string $key, $obj, array $arg = []): void
    {
        if (count($arg) == 1 && is_array($arg[0])) {
            $arg = $arg[0];
        }

        $this->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'])) {// 檢測(cè)參數(shù)是否為合法的可調(diào)用結(jié)構(gòu)(function,class method)
            return $result['obj'];
        } elseif (is_string($result['obj']) && class_exists($result['obj'])) {
            //通過反射方式獲取實(shí)例化對(duì)象
            $reflection = new \ReflectionClass($result['obj']);
            $constructor = $reflection->getConstructor();
                        $instance = null;
            if ($constructor->isPublic()) {//直接實(shí)例化
                $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的使用

//向容器中注入實(shí)例
//Di::getInstance()->set('redis', \App\Lib\Redis::getInstance($config));
Di::getInstance()->set('redis', \App\Lib\Redis::class, $config);

//通過容器獲取實(shí)例
$redisInstance = Di::getInstance()->get('redis');

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

總結(jié)

本案例涉及知識(shí)點(diǎn):
1.通過Yaconf擴(kuò)展高效獲取配置信息
2.static靜態(tài)綁定、trait特性
3.singleton模式的實(shí)現(xiàn)
4.Di依賴注入

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

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

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI