如何在 swoole 上做一个经典的 php exit()? 如何在 Laravel + Swoole 上替换 exit()

问题描述

例如这段代码

<?PHP
if (some_condition()) {
    header('Location: /');
    exit();
}

// do a lot of things...

在经典的 PHP FPM 上,以前的代码工作正常。但是在 PHP+Swoole 上,我们得到这个错误

swoole exit {"exception":"[object] (Swoole\\ExitException(code: 0): swoole exit at

这个错误是可以理解的。但是,迁移它的最简单方法是什么?

解决方法

对于 PHP FPM,每段代码都是单独执行的,结果(该过程的输出)通过管道返回给客户端。因此,每当我们想停止处理时,我们只需触发 exit()

然而,使用 Swoole,服务器应该一直运行。当然,可以使用 Swoole\Process::exit() stop the Process - 但通常由控制器来触发立即发送响应。例如:

$server = new Swoole\HTTP\Server("127.0.0.1",9501);

$server->on("start",function (Swoole\Http\Server $server) {
    echo "Swoole http server is started at http://127.0.0.1:9501\n";
});

$server->on("request",function (Swoole\Http\Request $request,Swoole\Http\Response $response) {
    $response->header("Content-Type","text/plain");
    $response->end("Hello World\n");
});

$server->start();

在这种情况下,$response->end 是与 PHP FPM 世界中的 exit() 基本相同的方法。请注意,它与 Node 世界中发生的情况非常相似:服务器应该一直运行,并且由控制器(处理每个单独请求的函数)决定是否停止处理单个请求并传回响应,包括标头和身体。

,

如何在 Laravel + Swoole 上替换 exit()

是的,exit() 函数是一种非常糟糕的做法。但是自己的 Laravel 应用程序会引导一个旧代码。那么,根据相关成本,这种方式是更好的解决方案。

  1. 做一个可渲染的异常
class ExitException extends Exception implements Renderable
{
    public function report() {
        return true; // dont report
    }

    public function render()
    {
        return ' '; // prevent 500 html dump error
    }
}
  1. exit(); 替换为
// exit;
throw new ExitException();

该异常将由您的应用程序错误处理程序处理,并向 Swoole 请求处理程序发送一个空字符串作为响应。

我再说一遍:这不是一个优雅的解决方案,只是防止更改旧应用程序上的大量代码。

,

您可以了解\Swoole\ExitException

use Swoole\Coroutine;
use function Swoole\Coroutine\run;

function route()
{
    controller();
}

function controller()
{
    your_code();
}

function your_code()
{
    Coroutine::sleep(.001);
    exit(1);
}

run(function () {
    try {
        route();
    } catch (\Swoole\ExitException $e) {
        var_dump($e->getMessage());
        var_dump($e->getStatus() === 1);
        var_dump($e->getFlags() === SWOOLE_EXIT_IN_COROUTINE);
    }
});