加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

看完这篇文章,就知道给 Laravel 开启 Swoole还可以不用三方包

发布时间:2020-12-13 21:01:51 所属栏目:PHP教程 来源:网络整理
导读:Swoole 是一款优秀的 PHP 扩展,利用其可以实现原生 PHP 很难做到的常驻服务和异步。正好我有个 Laravel 项目可以折腾,就研究了下。 点此加入我的企鹅群 Laravel 项目是基于 composer 的,所以我先帖下我的 composer.json 中的 require 声明: { "require":

Swoole 是一款优秀的 PHP 扩展,利用其可以实现原生 PHP 很难做到的常驻服务和异步。正好我有个 Laravel 项目可以折腾,就研究了下。

点此加入我的企鹅群

Laravel 项目是基于 composer 的,所以我先帖下我的 composer.json 中的 require 声明:

{
    "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,我们可选的包有这些:

swooletw/laravel-swoole

hhxsv5/laravel-s

但一般来说,项目中需要常驻容器的服务与每次均需重新构建的服务并不一样,所以我才剑走偏锋。

起步

我们需要将 public/index.php 替换成如下

<?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();

运行时发现大多数页面均没有问题,只有几个用了 infyomlabs/laravel-generator 产生的列表页,AJAX 拉取 JSON 时却返回了 HTML。

排查

在有问题页面的 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']);
        }
        ...
    }

这是判断 $this->request() 是不是 XHR 请求,且 Accept 请求头声明了 application/json

$this->request() 实现如下

/**

  • 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);
    }
}

就是从容器中取出 datatables.request 的过程。

所以我们只需让每次请求结束,$app 容器忘掉 datatables.request 就好了

改进

增加遗忘 datatables.request

$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 查询)

在这里插入图片描述

  • 注,此处给出的代码可以借鉴,但未经长期验证。且不同项目实际用到的包不同,需要在调试过程中 debug 容器中的服务提供者,和追踪代码来调优。

已知问题

  • flash 闪存数据以及表单验证错误的展示有问题

  • PDO 会报 Cannot execute queries while other unbuffered queries are active - https://github.com/symfony/symfony/issues/6745

  • Throttle 的 IP 获取设定默认会产生问题

点关注,不迷路

好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是人才。之前说过,PHP方面的技术点很多,也是因为太多了,实在是写不过来,写过来了大家也不会看的太多,所以我这里把它整理成了PDF和文档,如果有需要的可以

点击进入暗号: PHP+「平台」

在这里插入图片描述

在这里插入图片描述


更多学习内容可以访问【对标大厂】精品PHP架构师教程目录大全,只要你能看完保证薪资上升一个台阶(持续更新)

以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家,需要的可以加入我的 PHP技术交流群

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读