對 Hyperf 做的那些事 1

xiaoyin199發表於2020-01-02
  1. 作為一個PHPer一直思考PHP怎麼做高效能(個人基礎比較弱),怎麼微服務,之前真不知道,不是概念而是怎麼落地,談概念有用但是不落地有點扯
  2. Swoole沒有實際專案用過,swoole相關框架也沒了解過也不知道,獲取知道了可能對於之前的問題就可能有一些答案了
  3. Hyperf的出現簡直就是太及時了,文件清晰,框架靈活等等等,簡直不要太好
  4. 雖然Hyperf已經這麼好了,但是還是希望把它稍微按著自己喜歡的規範改造一下,這裡就把多有對它的改造都定義為自己的開發規範,如果大家覺得有道理可以沿用
  5. 感謝swoole團隊(韓老師等……),感謝Hyperf團隊(黃老師等……)

工欲善其事,必先利其器,它有個名字HyperfCMS

  1. 定義目錄結構

    ├─app                    應用目錄
    │  ……                   框架其它目錄
    │  ├─Core                核心目錄(都在這裡面)框架的修改,業務的核心都放在這個目錄下處理
    │  │  ├─Facade           服務容器中可用的類提供了一個「靜態」介面的類放在這個地方
    │  │  ├─HF               hyperf框架相關修改放於此
    │  │  ├─LogHandler       日誌處理
    │  │  ├─Repositories     倉庫目錄,業務邏輯處理,區分業務模組
    │  │  │  ├─Admin         後臺業務
    │  │  │  ├─Home          前臺業務
    │  │  │  ├─Api           介面業務
    │  │  ├─Services         服務目錄,業務邏輯處理,所有業務模組公用
    │  │  ├─common.php       公共函式檔案
    │  │  ├─Response.php     統一響應處理出口
  2. 呼叫邏輯設計

  1. 控制器----->倉庫----->服務----->模型(Model),解釋:http請求過來,通過路由找到控制器,控制器找到對應的倉庫,倉庫找到對應的服務,服務找到對應的模型,注意:為了規範,倉庫不可直接操作模型。
  2. 雖然hyperf提供了多種方法注入,但是個人覺的還是比較麻煩,如果引用類過多需要寫很多看著沒有實際用途的程式碼。所以進行了修改,隱式注入
  3. 隱式注入需要遵循約定的規範,如下:
  4. Controller需要繼承BaseController,且如果用到哪個倉庫需要在註釋裡@property \APP\Core\Repositories\TestRepository $testRepo目的是可以讓phpstorm可以函式間跳轉。
  5. 控制器呼叫倉庫的變數需要RepoRepository結尾,如:$testRepo
  6. 倉庫的命名必須用Repository結尾,如:TestRepository,需要繼承BaseRepository,如果用到服務需要@property \APP\Core\Services\TestService $testService目的是可以讓phpstorm可以函式間跳轉
  7. 倉內呼叫服務的變數需要Service結尾,如:$testService
  8. 服務的命名必須用Service結尾,如:TestService,需要繼承BaseService,如果用到model需要@property \APP\Models\Category $categoryModel, 目的是可以讓phpstorm可以函式間跳轉。
  9. 服務呼叫model的變數需要Model結尾,如:$categoryModel
  1. 貼程式碼

    class BaseController extends AbstractController
    {
        /**
         * __get 
         * 隱式注入倉庫類 
         * User:YM 
         * Date:2019/11/21 
         * Time:上午9:27 
         * @param $key
         * @return \Psr\Container\ContainerInterface|void
         */
        public function __get($key)
        {
            if ($key == 'app') {
                return $this->container;
              } else {
                $suffix = strstr($key,'Repo');
              if ($suffix && ($suffix == 'Repo' || $suffix == 'Repository')) {
                $repoName = $suffix == 'Repo' ? $key.'sitory':$key;
                return $this->getRepositoriesInstance($repoName);
              } else {
                throw new \RuntimeException("倉庫{$key}不存在,書寫錯誤!", StatusCode::ERR_SERVER);
              }
        }
    
        /**
         * getRepositoriesInstance 
         * 獲取倉庫類例項 
         * User:YM
         * Date:2019/11/21
         * Time:上午10:30
         * @param $key
         * @return mixed
         */
        public function getRepositoriesInstance($key)
        {
            $key = ucfirst($key);
            $module = $this->getModuleName();
          if (!empty($module)) {
                $module = "{$module}";
          } else {
                $module = "";
          }
        if ($module) {
            $filename = BASE_PATH."/app/Core/Repositories/{$module}/{$key}.php";
            $classname = "App\\Core\\Repositories\\{$module}\\{$key}";
        } else {
            $filename = BASE_PATH."/app/Core/Repositories/{$key}.php";
            $classname = "App\\Core\\Repositories\\{$key}";
        }
        if (file_exists($filename)) {
             return $this->container->get($classname);
          } else {
            throw new \RuntimeException("倉庫{$key}不存在,檔案不存在!", StatusCode::ERR_SERVER);
          }
        }
        /**
         * getModuleName 
         * 獲取所屬模組
         * User:YM 
         * Date:2019/11/21
         * Time:上午9:32 
         * @return string
         */
        private function getModuleName()
        {
            $classname = get_called_class();
          $name = substr($classname, 15);
          $space = explode('\\', $name);
          if(count($space) > 1){
                return $space[0];
          }else{
                return '';
          }
        }
    }
    /**
    * IndexController 
    * 類簡介
    * @package App\Controller
    * User:YM 
    * Date:2019/11/12 
    * Time:下午5:03 
    * @property \APP\Core\Repositories\TestRepository $testRepo
    */
    class IndexController extends BaseController 
    {
        public function index()
        {
            $this->testRepo->test();
        }
    }
    namespace App\Core\Repositories;
    use Psr\Container\ContainerInterface;
    use Hyperf\Di\Annotation\Inject;
    use App\Constants\StatusCode;
    /**
    * BaseRepository 
    * 倉庫基類 
    * @package App\Core\Repositories
    * User:YM
    * Date:2019/11/21
    * Time:下午2:36 
    */
    class BaseRepository
    {
    /**
    * @Inject
    * @var ContainerInterface
    */  
    protected $container;
    
    /**
    * __get
    * 隱式注入服務類 
    * User:YM 
    * Date:2019/11/21
    * Time:上午9:27 
    * @param $key
    * @return \Psr\Container\ContainerInterface|void
    */  
    public function __get($key)
    {
      if ($key == 'app') {
            return $this->container;
      } elseif (substr($key, -7) == 'Service') {
            return $this->getServiceInstance($key);
      } else {
            throw new \RuntimeException("服務{$key}不存在,書寫錯誤!", StatusCode::ERR_SERVER);
      }
    }
    
    /**
    * getServiceInstance 
    * 獲取服務類例項 
    * User:YM
    * Date:2019/11/21 
    * Time:上午10:30 
    * @param $key
    * @return mixed
    */  
    public function getServiceInstance($key)
    {
        $key = ucfirst($key);
         $fileName = BASE_PATH."/app/Core/Services/{$key}.php";
        $className = "App\\Core\\Services\\{$key}";
    
      if (file_exists($fileName)) {
                return $this->container->get($className);
      } else {
                throw new \RuntimeException("服務{$key}不存在,檔案不存在!", StatusCode::ERR_SERVER);
      }
    }
    }
    namespace App\Core\Repositories;
    /**
    * TestRepository
    * 類的介紹
    * @package App\Core\Repositories
    * User:YM
    * Date:2019/11/21
    * Time:上午10:25
    * @property \APP\Core\Services\TestService $testService
    */
    class TestRepository extends BaseRepository
    {
        public function test()
        {
            $tmp = $this->testService->test();
            return $tmp;
        }
    }
    namespace App\Core\Services;
    use Psr\Container\ContainerInterface;
    use Hyperf\Di\Annotation\Inject;
    use App\Constants\StatusCode;
    /**
    * BaseService
    * 服務基類
    * @package App\Core\Services
    * User:YM
    * Date:2019/11/21
    * Time:下午3:21
    */
    class BaseService
    {
    /**
     * @Inject
     * @var ContainerInterface
     */
    protected $container;
    
    /**
     * __get
     * 隱式注入服務類
     * User:YM
     * Date:2019/11/21
     * Time:上午9:27
     * @param $key
     * @return \Psr\Container\ContainerInterface|void
     */
    public function __get($key)
    {
        if ($key == 'app') {
            return $this->container;
        } elseif (substr($key, -5) == 'Model') {
            $key = strstr($key,'Model',true);
            return $this->getModelInstance($key);
        } elseif (substr($key, -7) == 'Service') {
            return $this->getServiceInstance($key);
        } else {
            throw new \RuntimeException("服務/模型{$key}不存在,書寫錯誤!", StatusCode::ERR_SERVER);
        }
    }
    
    /**
     * getModelInstance
     * 獲取資料模型類例項
     * User:YM
     * Date:2019/11/21
     * Time:上午10:30
     * @param $key
     * @return mixed
     */
    public function getModelInstance($key)
    {
        $key = ucfirst($key);
        $fileName = BASE_PATH."/app/Models/{$key}.php";
        $className = "App\\Models\\{$key}";
        if (file_exists($fileName)) {
            return $this->container->get($className);
        } else {
            throw new \RuntimeException("服務/模型{$key}不存在,檔案不存在!", StatusCode::ERR_SERVER);
        }
    }
    
    /**
     * getServiceInstance
     * 獲取服務類例項
     * User:YM
     * Date:2019/11/21
     * Time:上午10:30
     * @param $key
     * @return mixed
     */
    public function getServiceInstance($key)
    {
        $key = ucfirst($key);
        $fileName = BASE_PATH."/app/Services/{$key}.php";
        $className = "App\\Services\\{$key}";
    
        if (file_exists($fileName)) {
            return $this->container->get($className);
        } else {
            throw new \RuntimeException("服務/模型{$key}不存在,檔案不存在!", StatusCode::ERR_SERVER);
        }
     }
    }
    
    namespace App\Core\Services;

/**

  • TestServices
  • 類的介紹
  • @package App\Services
  • User:YM
  • Date:2019/11/21
  • Time:下午2:46
  • @property \APP\Models\Category $categoryModel
    */
    class TestService extends BaseService
    {
    public function test()
    {
    $tmp = $this->categoryModel->getList();
    return $tmp;
    }
    }
本作品採用《CC 協議》,轉載必須註明作者和本文連結

小尹你好!
成功細中取,寶貴險中求;細節決定成敗,態度決定一切。

相關文章