基於swoole框架進行二次封裝,php高性能業務框架編寫思路

swoole已是php高性能服務器事實標準,能夠參考這個博客使用swoole開發業務框架php

項目地址:github.com/neatlife/pf…html

歡迎star,歡迎prgit

框架執行的核心流程圖以下(右鍵可查看大圖): github

  1. 通用組件儘可能遵照psr進行實現,以提升對三方組件的兼容性
  2. 事件驅動

全局變量適配

swoole是從命令行啓動,常駐進程運行,web請求處理依賴的全局變量好比 _SERVER,_GET, _POST,_FILES等不會隨着每次請求的改變填上對應的值,swoole把這個每次請求的變量放在了Swoole\Http\Request對象中web

好比把swoole的request->server適配到全局變量_SERVER中json

$server = array_change_key_case($request->server, CASE_UPPER);
foreach ($request->header as $key => $val) {
    $server['HTTP_' . str_replace('-', '_', strtoupper($key))] = $val;
}
$_SERVER = $server;
複製代碼

其它環境變量的對應以下服務器

$_GET = $request->get;
$_POST = $request->post;
$_COOKIE = $request->cookie;
$_FILES = $request->files;
複製代碼

Symfony Console組件包裝

swoole的服務器從命令行啓動,使用這個Symfony Console組件包裝一下能夠方便的啓動swooleswoole

<?php
class SwooleServerCommand extends Command {
    // ...

    protected function execute(InputInterface $input, OutputInterface $output) {
        $options = $this->parseOption($input);
        $http = new HttpServer($options['host'], $options['port']);

        $swooleEventHandler = new SwooleEventHandler($this->container);
        foreach (self::$swooleEventList as $eventName) {
            $http->on($eventName, [$swooleEventHandler, 'on' . ucfirst($eventName)]);
        }
        echo "server started at {$options['host']}:{$options['port']}..." . PHP_EOL;
        $http->start();
    }

    // ...
}
複製代碼

Symfony EventDispatcher分發swoole事件

swoole的http事件經過swoole的回調函數觸發,這裏使用事件分發器,將這個框架的代碼儘量和swoole分離,實現鬆耦合目標cookie

這裏使用這個事件分發器處理了swoole的start和request事件composer

建立事件分發器對象

$this->eventDispatcher = new EventDispatcher();
複製代碼

分發start和request事件

class SwooleEventHandler {
    public function onStart() {
        Application::getInstance()->getEventDispatcher()->dispatch(Event::START, new GenericEvent());
    }

    public function onRequest(Request $request, Response $response) {
        $server = array_change_key_case($request->server, CASE_UPPER);
        foreach ($request->header as $key => $val) {
            $server['HTTP_' . str_replace('-', '_', strtoupper($key))] = $val;
        }
        $_SERVER = $server;

        Application::getInstance()->getEventDispatcher()->dispatch(Event::REQUEST, new GenericEvent($response));
    }
}
複製代碼

swoole完整的事件列表參考:wiki.swoole.com/wiki/page/4…

Symfony Dependency Injection提供對象容器

使用Symfony的容器來共享應用全部的對象,避免對象重複的建立,而且能夠在應用任何位置方便的獲取容器中的對象

建立容器

new ContainerBuilder();
複製代碼

設置對象

$this->container->set(Application::class, $this);
複製代碼

獲取對象

$this->container->get(Application::class);
複製代碼

Middleware處理http請求

中間件通常設計成嵌套調用,這種狀況下須要用遞歸來實現,核心代碼以下

protected function callMiddleware($request, $response, $index = 0) {
    if (!isset($this->middleware[$index])) {
        return $response;
    }

    $middleware = new $this->middleware[$index];
    return $middleware($request, $response, function ($request, $response) use ($index) {
        $this->callMiddleware($request, $response, $index + 1);
    });
}
複製代碼

composer.json

完整的composer.json依賴以下

"require": {
    "symfony/console": "^3.4",
    "symfony/event-dispatcher": "^3.4",
    "symfony/dependency-injection": "^3.4",
    "symfony/http-foundation": "^3.4"
},
"require-dev": {
    "phpunit/phpunit": "^6.0"
},
複製代碼

一些注意的點

symfony的Request對象沒有實現psr的ServerRequestInterface,若是要遵照psr的request,能夠考慮其它request組件,好比zend framework帶的request

參考資料

  1. www.php-fig.org/psr/
  2. wiki.swoole.com/wiki/page/3…

持續更新中...

相關文章
相關標籤/搜索