1. 程式人生 > >淺析easyswoole原始碼Di原理與實現

淺析easyswoole原始碼Di原理與實現

依賴注入

  簡介:Dependency Injection 依賴注入

  EasySwoole實現了簡單版的IOC,使用 IOC 容器可以很方便的儲存/獲取資源,實現解耦。

  使用依賴注入,最重要的一點好處就是有效的分離了物件和它所需要的外部資源,使得它們鬆散耦合,有利於功能複用,更重要的是使得程式的整個體系結構變得非常靈活。

  在我們的日常開發中,建立物件的操作隨處可見以至於對其十分熟悉的同時又感覺十分繁瑣,每次需要物件都需要親手將其new出來,甚至某些情況下由於壞程式設計習慣還會造成物件無法被回收,這是相當糟糕的。但更為嚴重的是,我們一直倡導的鬆耦合,少***原則,這種情況下變得一無是處。於是前輩們開始謀求改變這種程式設計陋習,考慮如何使用編碼更加解耦合,由此而來的解決方案是面向介面的程式設計。

  --摘自《searswoole開發文件》

本文將解析並實現下列功能。

  • 1、singleton模式的巧妙實現。
  • 2、通過Di方式實現簡單的容器,方便存取資源,從而達到解耦的目的。

程式碼實現

檔案結構

淺析easyswoole原始碼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);
    }
}