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 Awaitables, as only the consumption of Awaitables is required to be interoperable.
-
- Awaitable is an object implementing
Interop\Async\Awaitableand 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
throwstatement.
- Error is any value that can be thrown using the
-
- Reason is an error indicating why an
Awaitablehas 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 newThrowableinterface introduced in PHP 7. As this specification is PHP 5 compatible, we can't use neitherThrowablenorException.
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.