Eine schlanke Implementierung von CommonJS Promises/A für PHP.
Promise ist eine Bibliothek, die CommonJS Promises/A für PHP implementiert.
Es bietet auch mehrere andere nützliche Konzepte im Zusammenhang mit Versprechen, z. B. das Zusammenführen mehrerer Versprechen sowie das Zuordnen und Reduzieren von Sammlungen von Versprechen.
Wenn Sie noch nie von Versprechen gehört haben, lesen Sie dies zuerst.
Ein „Deferred“ stellt eine Berechnung oder Arbeitseinheit dar, die möglicherweise noch nicht abgeschlossen ist. Normalerweise (aber nicht immer) wird diese Berechnung asynchron ausgeführt und irgendwann in der Zukunft abgeschlossen.
Während ein Deferred die Berechnung selbst darstellt, stellt ein Promise das Ergebnis dieser Berechnung dar. Somit hat jeder Aufschub ein Versprechen, das als Platzhalter für sein tatsächliches Ergebnis fungiert.
Ein verzögerter Vorgang stellt einen Vorgang dar, dessen Lösung aussteht. Es verfügt über separate Promise- und Resolver-Teile.
$ deferred = new React Promise Deferred ();
$ promise = $ deferred -> promise ();
$ deferred -> resolve (mixed $ value );
$ deferred -> reject (Throwable $ reason );
Die promise
-Methode gibt das Versprechen des Verzögerten zurück.
Die resolve
und reject
steuern den Status des Zurückgestellten.
Der Konstruktor von Deferred
akzeptiert ein optionales $canceller
Argument. Weitere Informationen finden Sie unter Versprechen.
$ promise = $ deferred -> promise ();
Gibt das Versprechen des Zurückgestellten zurück, das Sie an andere weitergeben können, während Sie selbst die Befugnis behalten, seinen Zustand zu ändern.
$ deferred -> resolve (mixed $ value );
Löst das von promise()
zurückgegebene Versprechen auf. Alle Verbraucher werden benachrichtigt, indem $onFulfilled
(das sie über $promise->then()
registriert haben) mit $value
aufgerufen wird.
Wenn $value
selbst ein Versprechen ist, wird das Versprechen in den Zustand dieses Versprechens übergehen, sobald es gelöst ist.
Siehe auch die Funktion resolve()
.
$ deferred -> reject (Throwable $ reason );
Lehnt das von promise()
zurückgegebene Versprechen ab und signalisiert damit, dass die Berechnung des Verzögerten fehlgeschlagen ist. Alle Verbraucher werden benachrichtigt, indem $onRejected
(das sie über $promise->then()
registriert haben) mit $reason
aufgerufen wird.
Siehe auch die Funktion reject()
.
Die Promise-Schnittstelle stellt die gemeinsame Schnittstelle für alle Promise-Implementierungen bereit. Siehe Promise für die einzige öffentliche Implementierung, die von diesem Paket bereitgestellt wird.
Ein Versprechen stellt ein letztendliches Ergebnis dar, das entweder Erfüllung (Erfolg) und einen damit verbundenen Wert oder Ablehnung (Misserfolg) und einen damit verbundenen Grund ist.
Sobald ein Versprechen erfüllt oder abgelehnt ist, wird es unveränderlich. Weder sein Zustand noch sein Ergebnis (oder Fehler) können geändert werden.
$ transformedPromise = $ promise -> then (callable $ onFulfilled = null , callable $ onRejected = null );
Transformiert den Wert eines Versprechens, indem eine Funktion auf den Erfüllungs- oder Ablehnungswert des Versprechens angewendet wird. Gibt ein neues Versprechen für das transformierte Ergebnis zurück.
Die then()
Methode registriert neue erfüllte und abgelehnte Handler mit einem Versprechen (alle Parameter sind optional):
$onFulfilled
wird aufgerufen, sobald das Versprechen erfüllt ist und das Ergebnis als erstes Argument übergeben.$onRejected
wird aufgerufen, sobald das Versprechen abgelehnt wurde und der Grund als erstes Argument übergeben wird. Es gibt ein neues Versprechen zurück, das mit dem Rückgabewert von entweder $onFulfilled
oder $onRejected
erfüllt wird, je nachdem, was aufgerufen wird, oder es mit der ausgelösten Ausnahme ablehnt, wenn einer von beiden auslöst.
Ein Versprechen gewährleistet die folgenden Garantien für Handler, die im selben Aufruf von then()
registriert sind:
$onFulfilled
oder $onRejected
aufgerufen, niemals beide.$onFulfilled
und $onRejected
werden nie mehr als einmal aufgerufen. $ promise -> catch (callable $ onRejected );
Registriert einen Ablehnungshandler für ein Versprechen. Es ist eine Abkürzung für:
$ promise -> then ( null , $ onRejected );
Darüber hinaus können Sie das Argument $reason
von $onRejected
hint eingeben, um nur bestimmte Fehler abzufangen.
$ promise
-> catch ( function ( RuntimeException $ reason ) {
// Only catch RuntimeException instances
// All other types of errors will propagate automatically
})
-> catch ( function ( Throwable $ reason ) {
// Catch other errors
});
$ newPromise = $ promise -> finally (callable $ onFulfilledOrRejected );
Ermöglicht die Ausführung von Aufgaben vom Typ „Bereinigung“ in einer Versprechenskette.
Es sorgt dafür, dass $onFulfilledOrRejected
ohne Argumente aufgerufen wird, wenn das Versprechen entweder erfüllt oder abgelehnt wird.
$promise
erfüllt wird und $onFulfilledOrRejected
erfolgreich zurückgegeben wird, wird $newPromise
mit demselben Wert wie $promise
erfüllt.$promise
erfüllt wird und $onFulfilledOrRejected
ein abgelehntes Versprechen auslöst oder zurückgibt, lehnt $newPromise
mit der ausgelösten Ausnahme oder dem Grund des abgelehnten Versprechens ab.$promise
ablehnt und $onFulfilledOrRejected
erfolgreich zurückkehrt, lehnt $newPromise
mit demselben Grund wie $promise
ab.$promise
ablehnt und $onFulfilledOrRejected
ein abgelehntes Versprechen auslöst oder zurückgibt, lehnt $newPromise
mit der ausgelösten Ausnahme oder dem Grund des abgelehnten Versprechens ab. finally()
verhält sich ähnlich wie die synchrone „final“-Anweisung. In Kombination mit catch()
ermöglicht Ihnen finally()
das Schreiben von Code, der dem bekannten synchronen Paar „catch/finally“ ähnelt.
Betrachten Sie den folgenden synchronen Code:
try {
return doSomething ();
} catch ( Throwable $ e ) {
return handleError ( $ e );
} finally {
cleanup ();
}
Ähnlicher asynchroner Code (mit doSomething()
der ein Versprechen zurückgibt) kann geschrieben werden:
return doSomething ()
-> catch ( ' handleError ' )
-> finally ( ' cleanup ' );
$ promise -> cancel ();
Die Methode cancel()
benachrichtigt den Ersteller über das Versprechen, dass kein weiteres Interesse an den Ergebnissen der Operation besteht.
Sobald ein Versprechen erfüllt ist (entweder erfüllt oder abgelehnt), hat der Aufruf von cancel()
für ein Versprechen keine Auswirkung.
Seit Version 3.0.0 veraltet, siehe stattdessen
catch()
.
Die Methode otherwise()
registriert einen Ablehnungshandler für ein Versprechen.
Diese Methode existiert nur noch aus BC-Gründen und zur Vereinfachung von Upgrades zwischen Versionen. Es ist ein Alias für:
$ promise -> catch ( $ onRejected );
Seit Version 3.0.0 veraltet, siehe stattdessen
finally()
.
Mit der Methode always()
können Sie Aufgaben vom Typ „Bereinigung“ in einer Versprechenskette ausführen.
Diese Methode existiert nur noch aus BC-Gründen und zur Vereinfachung von Upgrades zwischen Versionen. Es ist ein Alias für:
$ promise -> finally ( $ onFulfilledOrRejected );
Erstellt ein Versprechen, dessen Status durch die an $resolver
übergebenen Funktionen gesteuert wird.
$ resolver = function ( callable $ resolve , callable $ reject ) {
// Do some work, possibly asynchronously, and then
// resolve or reject.
$ resolve ( $ awesomeResult );
// or throw new Exception('Promise rejected');
// or $resolve($anotherPromise);
// or $reject($nastyError);
};
$ canceller = function () {
// Cancel/abort any running operations like network connections, streams etc.
// Reject promise by throwing an exception
throw new Exception ( ' Promise cancelled ' );
};
$ promise = new React Promise Promise ( $ resolver , $ canceller );
Der Promise-Konstruktor erhält eine Resolver-Funktion und eine optionale Canceller-Funktion, die beide mit zwei Argumenten aufgerufen werden:
$resolve($value)
– Primäre Funktion, die das Schicksal des zurückgegebenen Versprechens besiegelt. Akzeptiert entweder einen nicht versprochenen Wert oder ein anderes Versprechen. Wenn es mit einem nicht versprochenen Wert aufgerufen wird, wird das Versprechen mit diesem Wert erfüllt. Wenn es mit einem anderen Versprechen aufgerufen wird, z. B. $resolve($otherPromise)
, entspricht das Schicksal des Versprechens dem von $otherPromise
.$reject($reason)
– Funktion, die das Versprechen ablehnt. Es wird empfohlen, einfach eine Ausnahme auszulösen, anstatt $reject()
zu verwenden.Wenn der Resolver oder Canceller eine Ausnahme auslöst, wird das Versprechen mit dieser ausgelösten Ausnahme als Ablehnungsgrund abgelehnt.
Die Resolver-Funktion wird sofort aufgerufen, die Canceller-Funktion erst, wenn alle Verbraucher die cancel()
Methode des Versprechens aufgerufen haben.
Nützliche Funktionen zum Erstellen und Zusammenführen von Versprechensammlungen.
Alle Funktionen, die an Promise-Sammlungen arbeiten (wie all()
, race()
usw.), unterstützen den Abbruch. Das heißt, wenn Sie cancel()
für das zurückgegebene Versprechen aufrufen, werden alle Versprechen in der Sammlung storniert.
$ promise = React Promise resolve (mixed $ promiseOrValue );
Erstellt ein Versprechen für den bereitgestellten $promiseOrValue
.
Wenn $promiseOrValue
ein Wert ist, ist dies der Auflösungswert des zurückgegebenen Versprechens.
Wenn $promiseOrValue
ein Thenable ist (jedes Objekt, das eine then()
Methode bereitstellt), wird ein vertrauenswürdiges Versprechen zurückgegeben, das dem Status des Thenable folgt.
Wenn $promiseOrValue
ein Versprechen ist, wird es unverändert zurückgegeben.
Das resultierende $promise
implementiert das PromiseInterface
und kann wie jedes andere Versprechen verwendet werden:
$ promise = React Promise resolve ( 42 );
$ promise -> then ( function ( int $ result ): void {
var_dump ( $ result );
}, function ( Throwable $ e ): void {
echo ' Error: ' . $ e -> getMessage () . PHP_EOL ;
});
$ promise = React Promise reject (Throwable $ reason );
Erstellt ein abgelehntes Versprechen für den angegebenen $reason
.
Beachten Sie, dass die in PHP 7 eingeführte Throwable
-Schnittstelle sowohl benutzerdefinierte Exception
's als auch Error
interne PHP-Fehler abdeckt. Indem Throwable
als Grund für die Ablehnung eines Versprechens erzwungen wird, kann jeder Sprachfehler oder jede User-Land-Ausnahme zur Ablehnung eines Versprechens genutzt werden.
Das resultierende $promise
implementiert das PromiseInterface
und kann wie jedes andere Versprechen verwendet werden:
$ promise = React Promise reject ( new RuntimeException ( ' Request failed ' ));
$ promise -> then ( function ( int $ result ): void {
var_dump ( $ result );
}, function ( Throwable $ e ): void {
echo ' Error: ' . $ e -> getMessage () . PHP_EOL ;
});
Beachten Sie, dass abgelehnte Versprechen immer ähnlich gehandhabt werden sollten, wie Ausnahmen immer in einem try
+ catch
-Block abgefangen werden sollten. Wenn Sie den letzten Verweis auf ein abgelehntes Versprechen entfernen, das nicht bearbeitet wurde, wird eine nicht behandelte Ablehnung des Versprechens gemeldet:
function incorrect (): int
{
$ promise = React Promise reject ( new RuntimeException ( ' Request failed ' ));
// Commented out: No rejection handler registered here.
// $promise->then(null, function (Throwable $e): void { /* ignore */ });
// Returning from a function will remove all local variable references, hence why
// this will report an unhandled promise rejection here.
return 42 ;
}
// Calling this function will log an error message plus its stack trace:
// Unhandled promise rejection with RuntimeException: Request failed in example.php:10
incorrect ();
Ein abgelehntes Versprechen gilt als „erledigt“, wenn Sie den Ablehnungsgrund entweder mit der then()
Methode, der catch()
Methode oder der finally()
Methode ermitteln. Beachten Sie, dass jede dieser Methoden ein neues Versprechen zurückgibt, das erneut abgelehnt werden kann, wenn Sie eine Ausnahme erneut auslösen.
Ein abgelehntes Versprechen gilt auch dann als „erledigt“, wenn Sie den Vorgang mit der Methode cancel()
abbrechen (die wiederum das Versprechen normalerweise ablehnt, wenn es noch aussteht).
Siehe auch die Funktion set_rejection_handler()
.
$ promise = React Promise all (iterable $ promisesOrValues );
Gibt ein Versprechen zurück, das erst dann aufgelöst wird, wenn alle Elemente in $promisesOrValues
aufgelöst wurden. Der Auflösungswert des zurückgegebenen Versprechens ist ein Array, das die Auflösungswerte aller Elemente in $promisesOrValues
enthält.
$ promise = React Promise race (iterable $ promisesOrValues );
Startet ein Wettbewerbsrennen, bei dem es einen Gewinner gibt. Gibt ein Versprechen zurück, das auf die gleiche Weise aufgelöst wird wie das erste abgewickelte Versprechen.
Das zurückgegebene Versprechen wird unendlich ausstehend, wenn $promisesOrValues
0 Elemente enthält.
$ promise = React Promise any (iterable $ promisesOrValues );
Gibt ein Versprechen zurück, das aufgelöst wird, wenn eines der Elemente in $promisesOrValues
aufgelöst wird. Der Auflösungswert des zurückgegebenen Versprechens ist der Auflösungswert des auslösenden Elements.
Das zurückgegebene Versprechen wird nur abgelehnt, wenn alle Elemente in $promisesOrValues
abgelehnt werden. Der Ablehnungswert ist eine ReactPromiseExceptionCompositeException
die alle Ablehnungsgründe enthält. Die Ablehnungsgründe können mit CompositeException::getThrowables()
ermittelt werden.
Das zurückgegebene Versprechen wird auch mit einer ReactPromiseExceptionLengthException
abgelehnt, wenn $promisesOrValues
0 Elemente enthält.
React Promise set_rejection_handler(?callable $ callback ): ?callable;
Legt den globalen Ablehnungshandler für nicht behandelte Versprechenablehnungen fest.
Beachten Sie, dass abgelehnte Versprechen immer ähnlich gehandhabt werden sollten, wie Ausnahmen immer in einem try
+ catch
-Block abgefangen werden sollten. Wenn Sie den letzten Verweis auf ein abgelehntes Versprechen entfernen, das nicht bearbeitet wurde, wird eine nicht behandelte Ablehnung des Versprechens gemeldet. Weitere Einzelheiten finden Sie auch in der Funktion reject()
.
Das ?callable $callback
Argument MUSS eine gültige Callback-Funktion sein, die ein einzelnes Throwable
-Argument oder einen null
akzeptiert, um den standardmäßigen Promise-Ablehnungshandler wiederherzustellen. Der Rückgabewert der Callback-Funktion wird ignoriert und hat keine Auswirkung, daher SOLLTEN Sie einen void
Wert zurückgeben. Die Rückruffunktion DARF NICHT ausgelöst werden, sonst wird das Programm mit einem schwerwiegenden Fehler beendet.
Die Funktion gibt den vorherigen Ablehnungshandler oder null
zurück, wenn der standardmäßige Versprechen-Ablehnungshandler verwendet wird.
Der Standard-Promise-Ablehnungshandler protokolliert eine Fehlermeldung und seinen Stack-Trace:
// Unhandled promise rejection with RuntimeException: Unhandled in example.php:2
React Promise reject ( new RuntimeException ( ' Unhandled ' ));
Der Promise-Ablehnungshandler kann verwendet werden, um die Protokollnachricht anzupassen oder in benutzerdefinierte Protokollziele zu schreiben. Als Faustregel gilt, dass diese Funktion nur als letzter Ausweg verwendet werden sollte und Versprechen-Ablehnungen am besten mit der Methode then()
, der Methode catch()
oder der Methode finally()
gehandhabt werden. Weitere Einzelheiten finden Sie auch in der Funktion reject()
.
function getAwesomeResultPromise ()
{
$ deferred = new React Promise Deferred ();
// Execute a Node.js-style function using the callback pattern
computeAwesomeResultAsynchronously ( function ( Throwable $ error , $ result ) use ( $ deferred ) {
if ( $ error ) {
$ deferred -> reject ( $ error );
} else {
$ deferred -> resolve ( $ result );
}
});
// Return the promise
return $ deferred -> promise ();
}
getAwesomeResultPromise ()
-> then (
function ( $ value ) {
// Deferred resolved, do something with $value
},
function ( Throwable $ reason ) {
// Deferred rejected, do something with $reason
}
);
Ein paar einfache Beispiele, um zu zeigen, wie die Mechanik der Promises/A-Weiterleitung funktioniert. Diese Beispiele sind natürlich erfunden, und in der Praxis werden Versprechensketten typischerweise über mehrere Funktionsaufrufe oder sogar mehrere Ebenen Ihrer Anwendungsarchitektur verteilt sein.
Aufgelöste Versprechen geben Auflösungswerte an das nächste Versprechen weiter. Das erste Versprechen, $deferred->promise()
, wird mit dem Wert aufgelöst, der unten an $deferred->resolve()
übergeben wird.
Jeder Aufruf von then()
gibt ein neues Versprechen zurück, das mit dem Rückgabewert des vorherigen Handlers aufgelöst wird. Dadurch entsteht eine Promise-„Pipeline“.
$ deferred = new React Promise Deferred ();
$ deferred -> promise ()
-> then ( function ( $ x ) {
// $x will be the value passed to $deferred->resolve() below
// and returns a *new promise* for $x + 1
return $ x + 1 ;
})
-> then ( function ( $ x ) {
// $x === 2
// This handler receives the return value of the
// previous handler.
return $ x + 1 ;
})
-> then ( function ( $ x ) {
// $x === 3
// This handler receives the return value of the
// previous handler.
return $ x + 1 ;
})
-> then ( function ( $ x ) {
// $x === 4
// This handler receives the return value of the
// previous handler.
echo ' Resolve ' . $ x ;
});
$ deferred -> resolve ( 1 ); // Prints "Resolve 4"
Abgelehnte Versprechen verhalten sich ähnlich und funktionieren auch ähnlich wie Try/Catch: Wenn Sie eine Ausnahme abfangen, müssen Sie sie erneut auslösen, damit sie sich weitergibt.
Wenn Sie mit einem abgelehnten Versprechen umgehen, können Sie die Ablehnung ebenfalls „erneut auslösen“, indem Sie entweder ein abgelehntes Versprechen zurückgeben oder es tatsächlich auslösen (da das Versprechen ausgelöste Ausnahmen in Ablehnungen umwandelt).
$ deferred = new React Promise Deferred ();
$ deferred -> promise ()
-> then ( function ( $ x ) {
throw new Exception ( $ x + 1 );
})
-> catch ( function ( Exception $ x ) {
// Propagate the rejection
throw $ x ;
})
-> catch ( function ( Exception $ x ) {
// Can also propagate by returning another rejection
return React Promise reject (
new Exception ( $ x -> getMessage () + 1 )
);
})
-> catch ( function ( $ x ) {
echo ' Reject ' . $ x -> getMessage (); // 3
});
$ deferred -> resolve ( 1 ); // Prints "Reject 3"
Genau wie bei Try/Catch können Sie wählen, ob Sie propagieren möchten oder nicht. Durch das Mischen von Auflösungen und Ablehnungen werden die Handler-Ergebnisse immer noch auf vorhersehbare Weise weitergeleitet.
$ deferred = new React Promise Deferred ();
$ deferred -> promise ()
-> then ( function ( $ x ) {
return $ x + 1 ;
})
-> then ( function ( $ x ) {
throw new Exception ( $ x + 1 );
})
-> catch ( function ( Exception $ x ) {
// Handle the rejection, and don't propagate.
// This is like catch without a rethrow
return $ x -> getMessage () + 1 ;
})
-> then ( function ( $ x ) {
echo ' Mixed ' . $ x ; // 4
});
$ deferred -> resolve ( 1 ); // Prints "Mixed 4"
Die empfohlene Methode zur Installation dieser Bibliothek ist Composer. Neu bei Composer?
Dieses Projekt folgt SemVer. Dadurch wird die neueste unterstützte Version aus diesem Zweig installiert:
composer require react/promise:^3.2
Einzelheiten zu Versionsaktualisierungen finden Sie auch im CHANGELOG.
Dieses Projekt zielt darauf ab, auf jeder Plattform ausgeführt zu werden, erfordert daher keine PHP-Erweiterungen und unterstützt die Ausführung auf PHP 7.1 bis zum aktuellen PHP 8+. Es wird dringend empfohlen, für dieses Projekt die neueste unterstützte PHP-Version zu verwenden .
Wir sind bestrebt, langfristige Supportoptionen (LTS) bereitzustellen und einen reibungslosen Upgrade-Pfad bereitzustellen. Wenn Sie eine ältere PHP-Version verwenden, können Sie den 2.x
Zweig (PHP 5.4+) oder 1.x
Zweig (PHP 5.3+) verwenden, die beide eine kompatible API bieten, aber nicht die Vorteile neuerer Sprachfunktionen nutzen. Sie können mehrere Versionen gleichzeitig als Ziel verwenden, um eine breitere Palette von PHP-Versionen wie diese zu unterstützen:
composer require " react/promise:^3 || ^2 || ^1 "
Um die Testsuite auszuführen, müssen Sie zunächst dieses Repo klonen und dann alle Abhängigkeiten über Composer installieren:
composer install
Um die Testsuite auszuführen, gehen Sie zum Projektstammverzeichnis und führen Sie Folgendes aus:
vendor/bin/phpunit
Darüber hinaus verwenden wir PHPStan auf maximalem Niveau, um die Typsicherheit im gesamten Projekt zu gewährleisten:
vendor/bin/phpstan
Promise ist eine Portierung von when.js von Brian Cavalier.
Außerdem wurden große Teile der Dokumentation aus dem when.js-Wiki und den API-Dokumenten portiert.
Veröffentlicht unter der MIT-Lizenz.