The goal of this specification is to define an Awaitable
interface for interoperability in PHP.
An Awaitable
represents the eventual result of an asynchronous operation. The primary way of interacting with an Awaitable
is through its when
method, which registers a callback to receive either an Awaitable
's eventual value or the reason why the Awaitable
has failed. They're basically the same as a Promise
in JavaScript's Promises/A+ specification, but the interaction with them is different as the following paragraphs show.
This specification defines an interoperable Awaitable
interface for PHP, focussing on its when
method. This is required for interoperable co-routines, which can be implemented in PHP using generators. Further methods like a watch
method for progress updates are out of scope of this specification. The name Awaitable
works well if PHP is extended later to support await
and is also alraedy used in HHVM.
Awaitable
is the fundamental primitive in asynchronous programming. It should be as lightweight as possible, as any cost adds up significantly. The existing Promises/A+ specification conflicts with the goal of lightweight primitives.
Co-routines should be the preferred way of writing asynchronous code, as it allows the use of try
/ catch
and doesn't result in a so-called callback hell. Co-routines do not use the returned Promise
of a then
callback, but returning a Promise
is required by Promises/A+. This means a lot of useless object creations, which aren't cheap and add up.
Existing libraries using Promises/A+ can easily additionally implement Awaitable
to be interoperable, while still supporting their current chainability using then
.
This specification does not deal with how to create, succeed or fail Awaitable
s, as only the consumption of Awaitable
s is required to be interoperable.
-
- Awaitable is an object implementing
Interop\Async\Awaitable
and conforming to this specification.
- Awaitable is an object implementing
-
- Value is any legal PHP value (including
null
), except an instance ofInterop\Async\Awaitable
.
- Value is any legal PHP value (including
-
- Error is any value that can be thrown using the
throw
statement.
- Error is any value that can be thrown using the
-
- Reason is an error indicating why an
Awaitable
has failed.
- Reason is an error indicating why an
An Awaitable
MUST be in one of three states: pending
, succeeded
, failed
.
A promise in … state | |
---|---|
pending |
|
succeeded |
|
failed |
|
- Must not change refers to the reference being immutable in case of an object, not the object itself being immutable.
An Awaitable
MUST implement Interop\Async\Awaitable
and thus provide a when
method to access its current or eventual value or reason.
<?php
namespace Interop\Async\Awaitable;
interface Awaitable
{
/** @return void */
function when(callable $callback);
}
The when
method MUST accept at least one argument:
$callback
– A callable conforming to the following signature:
function($error, $value) { /* ... */ }
Any implementation MUST at least provide these two parameters. The implementation MAY extend the Awaitable
interface with additional parameters passed to the callback. Further arguments to when
MUST have default values, so when
can always be called with only one argument. Callbacks MAY decide to consume only one or none of the provided parameters. when
MUST NOT return a value.
NOTE: The signature doesn't specify a type for
$error
. This is due to the newThrowable
interface introduced in PHP 7. As this specification is PHP 5 compatible, we can't use neitherThrowable
norException
.
All registered callbacks MUST be executed in the order they were registered. If one of the callbacks throws an Exception
or Throwable
, it MUST be rethrown in a callable passed to Loop::defer
so Loop::onError
can be properly invoked by the loop. Loop
refers to the global event loop accessor. The Awaitable
implementation MUST then continue to call the remaining callbacks with the original reason.
When an Awaitable
is resolved with another Awaitable
, the Awaitable
MUST keep in pending state until the passed Awaitable
is resolved. Thus, the value of an Awaitable
can never be another Awaitable
.