基于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…

持续更新中...

相关文章
相关标签/搜索