0

Here's a simple event loop with a ReactPHP promise:

new React\Http\Server([
    function(ServerRequestInterface $request) {
        $deferred = new React\Promise\Deferred();
        $promise = $deferred->promise();

        $deferred->reject(new Response(500));

        return $promise;
    }
]);

In this case everything works fine and the server returns 500, because the promise was returned and it was rejected.

But how to handle cases like this:

new React\Http\Server([
    function(ServerRequestInterface $request) {
        $deferred = new React\Promise\Deferred();
        $promise = $deferred->promise();

        SynTaxErrO..2!((r();

        $deferred->reject(new Response(500));

        return $promise;
    }
]);

The server/loop will still be running, but the connection will be hanging, since a syntax error happened before the promise was returned.

My first assumption was to use try-catch, but it doesn't seem to work in PHP.

try {
    SynTaxErrO..2!((r();
} catch($e) {
    $deferred->reject(new Response(500));
    return $promise;
}

Is there a way to deal with cases like this and still return 500 instead of just hanging and waiting for a promise that was never returned? In real code I have a router function that returns a promise. The promise is never retuned if one of the routes have a syntax error, and thus the connection just hangs. There are no error messages as well.

Daniel J F
  • 1,054
  • 2
  • 15
  • 29

2 Answers2

1

Hey ReactPHP team member here. Looks like the culput of you issue is SynTaxErrO..2!((r();, PHP can't parse that: https://3v4l.org/02cli

The best solution is not to have any syntax errors. A package that you could use to lint all your files before committing/deploying is: https://github.com/JakubOnderka/PHP-Parallel-Lint

WyriHaximus
  • 1,000
  • 6
  • 8
  • Hey. Thanks for the answer! It looks like we had several issues there. Sometimes it's syntax errors, sometimes typos (execution of functions that don't exist), etc., since it's the active development phase. The problem was that none of the errors were caught, and the log was empty. The solution seems to be: 1) always lint files, 2) define `otherwise` for all promises, 3) catch `React\Http\Server` errors (`$server->on('error', $fn);`) – Daniel J F Aug 22 '18 at 08:16
  • 2
    `$server->on('error')` should catch all errors occuring duing the handler execution so that is your prima source of errors during execution. The issue with 2) is that your error occurs outside the promise scope. But when it could happen within your promise scope I would suggest using `->done()` after your last `then` e.g. `->then($fn)->done();` which will throw any unhandled exceptions from within promises. – WyriHaximus Aug 22 '18 at 14:37
  • 1
    Thank you @WyriHaximus I finally found my exceptions by calling `->done()` at the end. – TiMESPLiNTER Jan 27 '21 at 13:13
1

You cannot catch syntax errors. If there is a syntax error before your catch statement, then execution never reaches your catch and therefore is like it didn't exist. To detect syntax error use a linter (for instance, php -l) before executing your code.

For other kinds of errors, provided you are using PHP 7, then you can use

catch (Error $e) { ... }

or a set_exception_handler() handler to catch errors.

If you want to catch both errors and exceptions, then you can use a block like

catch (Throwable $e) { ... }

If you only want to catch exceptions, use

catch (Exception $e) { ... }

See http://php.net/manual/en/language.errors.php7.php for more info

Javi Stolz
  • 4,720
  • 1
  • 30
  • 27
  • Copy/pasting my reply to @WyriHaximus, in case someone else is looking for error handing in ReactPHP: It looks like we had several issues there. Sometimes it's syntax errors, sometimes typos (execution of functions that don't exist), etc., since it's the active development phase. The problem was that none of the errors were caught, and the log was empty. The solution seems to be: 1) always lint files, 2) define `otherwise` for all promises, 3) catch `React\Http\Server` errors (`$server->on('error', $fn);`). All three are required. – Daniel J F Aug 22 '18 at 08:19