swoole已是php高性能服務器事實標準,能夠參考這個博客使用swoole開發業務框架php
項目地址:github.com/neatlife/pf…html
歡迎star,歡迎prgit
框架執行的核心流程圖以下(右鍵可查看大圖): github
swoole是從命令行啓動,常駐進程運行,web請求處理依賴的全局變量好比 _GET, _FILES等不會隨着每次請求的改變填上對應的值,swoole把這個每次請求的變量放在了Swoole\Http\Request對象中web
好比把swoole的_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;
複製代碼
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();
}
// ...
}
複製代碼
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的容器來共享應用全部的對象,避免對象重複的建立,而且能夠在應用任何位置方便的獲取容器中的對象
new ContainerBuilder();
複製代碼
$this->container->set(Application::class, $this);
複製代碼
$this->container->get(Application::class);
複製代碼
中間件通常設計成嵌套調用,這種狀況下須要用遞歸來實現,核心代碼以下
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依賴以下
"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
持續更新中...