不用三方包 给 Laravel 开启 Swoole
Swoole?是一款优秀的 PHP 扩展,利用其可以实现原生 PHP 很难做到的常驻服务和异步。正好我有个 Laravel 项目可以折腾,就研究了下。 Laravel 项目是基于 composer 的,所以我先帖下我的? ? { "require": { "php": "^7.1.3","cybercog/laravel-love": "^5.1","dingo/api": "~v2.0.0-alpha2","doctrine/dbal": "^2.8","fideloper/proxy": "^4.0","guzzlehttp/guzzle": "^6.3","infyomlabs/adminlte-templates": "5.6.x-dev","infyomlabs/laravel-generator": "5.6.x-dev","jeroennoten/laravel-adminlte": "^1.23","laravel/framework": "5.6.*","laravel/tinker": "^1.0","laravelcollective/html": "^5.6.0","lshorz/luocaptcha": "^1.0","overtrue/laravel-lang": "v3.0.08","overtrue/laravel-wechat": "^4.0","predis/predis": "^1.1","spatie/laravel-permission": "^2.17","tymon/jwt-auth": "~1.0.0-rc.2","yajra/laravel-datatables-buttons": "^4.0","yajra/laravel-datatables-oracle": "^8.7" } }
如果我们要开启 swoole,我们可选的包有这些:
但一般来说,项目中需要常驻容器的服务与每次均需重新构建的服务并不一样,所以我才剑走偏锋。 起步我们需要将? <?php use IlluminateHttpRequest; use IlluminateHttpResponse; define('LARAVEL_START',microtime(true)); require __DIR__ . '/../vendor/autoload.php'; $app = require_once __DIR__ . '/../bootstrap/app.php'; class Laravel { /** * IlluminateFoundationApplication * * @var IlluminateFoundationApplication */ public $app; /** * AppHttpKernel * * @var AppHttpKernel */ public $kernel; /** * AppHttpRequestsRequest * * @var AppHttpRequestsRequest */ public $request; /** * IlluminateHttpJsonResponse * * @var IlluminateHttpJsonResponse */ public $response; /** * 构造 * * @param IlluminateFoundationApplication $app */ public function __construct(IlluminateFoundationApplication $app) { $this->app = $app; } /** * RUN * * @return void */ public function run() { SwooleRuntime::enableCoroutine(true); $http = new swoole_http_server('127.0.0.1','80'); $http->set([ 'document_root' => public_path('/'),'enable_static_handler' => true,]); $http->on('request',function ($req,$res) { try { $kernel = $this->app->make(IlluminateContractsHttpKernel::class); $get = $req->get ?? []; $post = $req->post ?? []; $input = array_merge($get,$post); $cookie = $req->cookie ?? []; $files = $req->files ?? []; $server = $req->server ?? []; $request = Request::create($req->server['request_uri'],$req->server['request_method'],$input,$cookie,$files,$server); if (isset($req->header['x-requested-with']) && $req->header['x-requested-with'] == "XMLHttpRequest") { $request->headers->set('X-Requested-With',"XMLHttpRequest",true); } if (isset($req->header['accept']) && $req->header['accept']) { $request->headers->set('Accept',$req->header['accept'],true); } $response = $kernel->handle($request); $res->status($response->getStatusCode()); foreach ($response->headers->allPreserveCaseWithoutCookies() as $name => $values) { foreach ($values as $value) { $res->header($name,$value,false); } } foreach ($response->headers->getCookies() as $cookie) { $res->header('Set-Cookie',$cookie->getName() . strstr($cookie,'='),false); } dump(time()); $res->end($response->getContent()); $this->app->forgetInstance('request'); } catch (throwable $e) { echo $e->getMessage(); echo PHP_EOL; echo $e->getFile(); echo PHP_EOL; echo $e->getLine(); echo PHP_EOL; } }); $http->start(); } } (new Laravel($app))->run();
运行时发现大多数页面均没有问题,只有几个用了? 排查在有问题页面的 controller 代码中,找到如下 /** * Display a listing of the Star. * * @param StarDataTable $starDataTable * @return Response */ public function index(StarDataTable $starDataTable) { return $starDataTable->render('stars.index'); } 定位 StarDataTable::render() 到了 /** * Process dataTables needed render output. * * @param string $view * @param array $data * @param array $mergeData * @return mixed */ public function render($view,$data = [],$mergeData = []) { if ($this->request()->ajax() && $this->request()->wantsJson()) { return app()->call([$this,'ajax']); } ... }
这是判断? 而? /** * Get DataTables Request instance. * * @return YajraDataTablesUtilitiesRequest */ public function request() { return $this->request ?: $this->request = resolve('datatables.request'); }
不难看出,如果第一次构建,会走到 $this->request = resolve('datatables.request');
而 resolve 的实现是啥? if (! function_exists('resolve')) { /** * Resolve a service from the container. * * @param string $name * @return mixed */ function resolve($name) { return app($name); } }
就是从容器中取出? 所以我们只需让每次请求结束,$app 容器忘掉? 改进增加遗忘? $res->end($response->getContent()); $this->app->forgetInstance('request'); $this->app->forgetInstance('datatables.request'); $this->app->forgetInstance(DingoApiHttpMiddlewareRequest::class);
完整最终版: <?php use IlluminateHttpRequest; use IlluminateHttpResponse; define('LARAVEL_START',false); } dump(time()); $res->end($response->getContent()); $this->app->forgetInstance('request'); //$this->app->forgetInstance('session'); //$this->app->forgetInstance('session.store'); //$this->app->forgetInstance('cookie'); $this->app->forgetInstance('datatables.request'); $this->app->forgetInstance(DingoApiHttpMiddlewareRequest::class); //$kernel->terminate($request,$response); } catch (throwable $e) { echo $e->getMessage(); echo PHP_EOL; echo $e->getFile(); echo PHP_EOL; echo $e->getLine(); echo PHP_EOL; } }); $http->start(); } } (new Laravel($app))->run();
测试比原生 laravel 确实快不少(这还有 4 句 SQL 查询) 。 注,此处给出的代码可以借鉴,但未经长期验证。且不同项目实际用到的包不同,需要在调试过程中? 已知问题
更多学习内容请访问: 腾讯T3-T4标准精品PHP架构师教程目录大全,只要你看完保证薪资上升一个台阶(持续更新) ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |