phasync
phasync / run

Method

phasync::run

Runs $fn and returns its result once it and every coroutine started inside it have ended.

Description#

public static phasync::run(
    callable $fn,
    mixed ...$args
): mixed

Outside a coroutine, run() starts the event loop, runs $fn as a coroutine and blocks the process until then. This is how a script, a test or a controller under PHP-FPM enters phasync. Inside a coroutine it runs $fn in that coroutine, in a new frame: the calling coroutine waits for what $fn started, and the others go on. A nested run() costs no coroutine, so a server can give each request one.

Every run() creates a Frame: the coroutines started inside it belong to it, also those started by its coroutines, and it waits for them. A failure does not cancel the others. Once they have all ended, run() throws every failure: what $fn threw and each failure of a coroutine nobody awaited (a later await counts, until run() ends). One is thrown as it is; several in an AggregateException, $fn's first, then by the time they happened. Without failures it returns what $fn returned. A coroutine that ends with a cancellation phasync issued is no failure. With an exception handler on the frame (Frame::setExceptionHandler), the failures nobody awaited go to it instead. When coroutines wait and nothing can ever wake them, the outermost run() cancels its coroutines and throws a DeadlockException.

When the outermost run() has no coroutine left, it cancels the services (phasync::service) and returns once they have ended. run() does not change the current Scope: $fn runs in the caller's.

Parameters#

$fn callable
What to run
...$args mixed
Passed to $fn

Return values#

What $fn returned mixed

Errors / Exceptions#

ExceptionWhen
ThrowableWhat $fn threw, or the failure of a coroutine nobody awaited, when there is one
AggregateExceptionWhen there are several
TimeoutExceptionWhen the frame's deadline passed (Frame::setTimeout)
DeadlockExceptionFrom the outermost run(), when coroutines wait and nothing can wake them
LogicExceptionInside the event loop but outside a coroutine (an onScopeChange() hook)

Examples#

Example 1
$result = phasync::run(function () {
    phasync::go(function () {
        phasync::sleep(0.1);
        echo "second\n";
    });
    echo "first\n";

    return 'done';
});
echo "third: $result\n";    // run() returned after the coroutine ended

See also#

  • phasync::goStarts a coroutine without waiting for it
  • phasync::frameReturns the frame of the running coroutine: that of the innermost run() it is in.
  • phasync::awaitWaits for a coroutine or a promise, and returns its result or throws the exception it ended with.
  • phasync::serviceStarts $fn as a service: a coroutine of no frame, in the root scope, which outlives the code that started it, and returns it.
  • DeadlockExceptionCoroutines wait, and nothing can ever wake them: the outermost run() throws this.