PHP 用 CommonJS Promises/A の軽量実装。
Promise は、PHP 用 CommonJS Promises/A を実装するライブラリです。
また、複数の Promise の結合、Promise のコレクションのマッピングと削減など、他のいくつかの便利な Promise 関連の概念も提供します。
これまでに Promise について聞いたことがない場合は、まずこれを読んでください。
Deferred は、まだ完了していない可能性がある計算または作業単位を表します。通常 (常にではありませんが)、その計算は非同期で実行され、将来のある時点で完了します。
deferred は計算自体を表しますが、 Promise はその計算の結果を表します。したがって、それぞれの遅延には、実際の結果のプレースホルダーとして機能する Promise があります。
deferred は、解決が保留中の操作を表します。これには個別のプロミス部分とリゾルバー部分があります。
$ deferred = new React Promise Deferred ();
$ promise = $ deferred -> promise ();
$ deferred -> resolve (mixed $ value );
$ deferred -> reject (Throwable $ reason );
promise
メソッドは、遅延された Promise を返します。
resolve
メソッドとreject
メソッドは、遅延の状態を制御します。
Deferred
のコンストラクターは、オプションの$canceller
引数を受け入れます。詳細については、「約束」を参照してください。
$ promise = $ deferred -> promise ();
deferred の Promise を返します。これは、状態を変更する権限を自分に保持したまま、他の人に渡すことができます。
$ deferred -> resolve (mixed $ value );
promise()
によって返された Promise を解決します。すべてのコンシューマーは、 $onFulfilled
( $promise->then()
経由で登録) を$value
で呼び出すことによって通知されます。
$value
自体が Promise である場合、Promise は解決されるとこの Promise の状態に遷移します。
resolve()
関数」も参照してください。
$ deferred -> reject (Throwable $ reason );
promise()
によって返された Promise を拒否し、遅延の計算が失敗したことを示します。すべてのコンシューマーは、 $reason
を使用して$onRejected
( $promise->then()
経由で登録) を呼び出すことによって通知されます。
「 reject()
関数」も参照してください。
Promise インターフェイスは、すべての Promise 実装に共通のインターフェイスを提供します。このパッケージによって公開される唯一のパブリック実装については、「Promise」を参照してください。
Promise は、履行 (成功) とそれに関連する値、または拒否 (失敗) とそれに関連する理由のいずれかの最終的な結果を表します。
履行または拒否された状態になると、Promise は不変になります。状態も結果 (またはエラー) も変更できません。
$ transformedPromise = $ promise -> then (callable $ onFulfilled = null , callable $ onRejected = null );
Promise の履行値または拒否値に関数を適用して、Promise の値を変換します。変換された結果に対する新しい Promise を返します。
then()
メソッドは、新しい履行ハンドラーと拒否ハンドラーを Promise に登録します (すべてのパラメーターはオプションです)。
$onFulfilled
、Promise が履行され、結果が最初の引数として渡されると呼び出されます。$onRejected
Promise が拒否され、その理由が最初の引数として渡されると呼び出されます。 $onFulfilled
または$onRejected
いずれかが呼び出された場合の戻り値で満たされるか、どちらかがスローされた場合はスローされた例外で拒否される新しい Promise を返します。
Promise は、 then()
への同じ呼び出しに登録されたハンドラーについて次の保証を行います。
$onFulfilled
または$onRejected
のいずれか 1 つだけが呼び出され、両方が呼び出されることはありません。$onFulfilled
と$onRejected
複数回呼び出されることはありません。 $ promise -> catch (callable $ onRejected );
Promise の拒否ハンドラーを登録します。これは次のショートカットです。
$ promise -> then ( null , $ onRejected );
さらに、 $onRejected
の$reason
引数にヒントを入力して、特定のエラーのみをキャッチすることができます。
$ 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 );
Promise チェーンで「クリーンアップ」タイプのタスクを実行できるようにします。
Promise が履行または拒否されたときに、引数なしで$onFulfilledOrRejected
呼び出されるように手配します。
$promise
が満たされ、 $onFulfilledOrRejected
正常に返された場合、 $newPromise
$promise
と同じ値で満たされます。$promise
が満たされ、 $onFulfilledOrRejected
拒否された Promise をスローまたは返す場合、 $newPromise
スローされた例外または拒否された Promise の理由で拒否します。$promise
拒否し、 $onFulfilledOrRejected
正常に返された場合、 $newPromise
$promise
と同じ理由で拒否します。$promise
が拒否し、 $onFulfilledOrRejected
拒否された Promise をスローまたは返す場合、 $newPromise
スローされた例外または拒否された Promise の理由で拒否します。 finally()
同期の Final ステートメントと同様に動作します。 catch()
と組み合わせると、 finally()
を使用すると、よく知られた同期の catch/finally ペアに似たコードを作成できます。
次の同期コードを考えてみましょう。
try {
return doSomething ();
} catch ( Throwable $ e ) {
return handleError ( $ e );
} finally {
cleanup ();
}
同様の非同期コード (Promise を返すdoSomething()
を使用) を作成できます。
return doSomething ()
-> catch ( ' handleError ' )
-> finally ( ' cleanup ' );
$ promise -> cancel ();
cancel()
メソッドは、Promise の作成者に、操作の結果にそれ以上の関心がないことを通知します。
Promise が解決されると (履行または拒否され)、Promise でcancel()
を呼び出しても効果はありません。
v3.0.0 以降非推奨になりました。代わりに
catch()
参照してください。
otherwise()
メソッドは、Promise の拒否ハンドラーを登録します。
この方法は、BC 上の理由と、バージョン間のアップグレードを容易にするためにのみ存在し続けます。これは次のエイリアスです。
$ promise -> catch ( $ onRejected );
v3.0.0 以降非推奨になりました。代わりに、
finally()
参照してください。
always()
メソッドを使用すると、Promise チェーンで「クリーンアップ」タイプのタスクを実行できます。
この方法は、BC 上の理由と、バージョン間のアップグレードを容易にするためにのみ存在し続けます。これは次のエイリアスです。
$ promise -> finally ( $ onFulfilledOrRejected );
$resolver
に渡される関数によって状態が制御される Promise を作成します。
$ 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 );
Promise コンストラクターは、リゾルバー関数とオプションのキャンセラー関数を受け取ります。これらは両方とも 2 つの引数で呼び出されます。
$resolve($value)
- 返された Promise の運命を決定する主な関数。非 Promise 値または別の Promise のいずれかを受け入れます。非promise値で呼び出された場合、その値でpromiseを実行します。別の Promise、たとえば$resolve($otherPromise)
で呼び出された場合、Promise の運命は$otherPromise
の運命と同等になります。$reject($reason)
- Promise を拒否する関数。 $reject()
使用する代わりに、単に例外をスローすることをお勧めします。リゾルバーまたはキャンセラーが例外をスローした場合、そのスローされた例外を拒否理由として Promise は拒否されます。
リゾルバー関数はすぐに呼び出されますが、キャンセラー関数はすべてのコンシューマーがプロミスのcancel()
メソッドを呼び出したときにのみ呼び出されます。
Promise のコレクションを作成および結合するための便利な関数。
Promise コレクションで動作するすべての関数 ( all()
、 race()
など) はキャンセルをサポートしています。つまり、返された Promise に対してcancel()
を呼び出すと、コレクション内のすべての Promise がキャンセルされます。
$ promise = React Promise resolve (mixed $ promiseOrValue );
指定された$promiseOrValue
の Promise を作成します。
$promiseOrValue
が値の場合、それは返された Promise の解決値になります。
$promiseOrValue
が thenable ( then()
メソッドを提供する任意のオブジェクト) の場合、thenable の状態に従う信頼された Promise が返されます。
$promiseOrValue
が Promise の場合は、そのまま返されます。
結果の$promise
PromiseInterface
を実装し、他の Promise と同様に使用できます。
$ 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 );
指定された$reason
に対して拒否された Promise を作成します。
PHP 7 で導入されたThrowable
インターフェイスは、ユーザーランドのException
とError
内部 PHP エラーの両方をカバーすることに注意してください。 Promise を拒否する理由としてThrowable
強制することにより、言語エラーやユーザーランド例外を Promise の拒否に使用できます。
結果の$promise
PromiseInterface
を実装し、他の Promise と同様に使用できます。
$ 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 ;
});
拒否された Promise は常に、例外がtry
+ catch
ブロックでキャッチされるのと同様に処理される必要があることに注意してください。処理されていない拒否された Promise への最後の参照を削除すると、未処理の Promise 拒否が報告されます。
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 ();
then()
メソッド、 catch()
メソッド、またはfinally()
メソッドのいずれかを使用して拒否の理由をキャッチした場合、拒否された Promise は「処理された」とみなされます。これらの各メソッドは新しい Promise を返しますが、例外を再スローすると再び拒否される可能性があることに注意してください。
cancel()
メソッドで操作を中止した場合、拒否された Promise も「処理された」とみなされます (通常、まだ保留中の Promise は拒否されます)。
set_rejection_handler()
関数も参照してください。
$ promise = React Promise all (iterable $ promisesOrValues );
$promisesOrValues
内のすべての項目が解決された場合にのみ解決される Promise を返します。返される Promise の解決値は、 $promisesOrValues
内の各項目の解決値を含む配列になります。
$ promise = React Promise race (iterable $ promisesOrValues );
1 人の勝者を許可する競争レースを開始します。最初に解決された Promise が解決されるのと同じ方法で解決される Promise を返します。
$promisesOrValues
に項目が 0 個含まれている場合、返された Promise は無限に保留状態になります。
$ promise = React Promise any (iterable $ promisesOrValues );
$promisesOrValues
内の項目のいずれかが解決されると解決される Promise を返します。返された Promise の解決値は、トリガー項目の解決値になります。
返された Promise は、 $promisesOrValues
内のすべての項目が拒否された場合にのみ拒否されます。拒否値は、すべての拒否理由を保持するReactPromiseExceptionCompositeException
になります。拒否の理由はCompositeException::getThrowables()
で取得できます。
$promisesOrValues
に項目が 0 個含まれている場合、返された Promise はReactPromiseExceptionLengthException
で拒否されます。
React Promise set_rejection_handler(?callable $ callback ): ?callable;
未処理の Promise 拒否に対するグローバル拒否ハンドラーを設定します。
拒否された Promise は常に、例外がtry
+ catch
ブロックでキャッチされるのと同様に処理される必要があることに注意してください。処理されていない拒否された Promise への最後の参照を削除すると、未処理の Promise 拒否が報告されます。詳細については、 reject()
関数も参照してください。
?callable $callback
引数は、単一のThrowable
引数またはデフォルトの Promise 拒否ハンドラを復元するためのnull
値を受け入れる有効なコールバック関数でなければなりません。コールバック関数の戻り値は無視され、効果がないため、 void
値を返す必要があります。コールバック関数をスローしてはなりません。スローしないと、プログラムが致命的なエラーで終了します。
この関数は、以前の拒否ハンドラーを返すか、デフォルトの Promise 拒否ハンドラーを使用している場合はnull
返します。
デフォルトの Promise 拒否ハンドラーは、エラー メッセージとそのスタック トレースをログに記録します。
// Unhandled promise rejection with RuntimeException: Unhandled in example.php:2
React Promise reject ( new RuntimeException ( ' Unhandled ' ));
Promise 拒否ハンドラーを使用して、ログ メッセージをカスタマイズしたり、カスタム ログ ターゲットに書き込んだりすることができます。経験則として、この関数は最後の手段としてのみ使用する必要があり、Promise の拒否はthen()
メソッド、 catch()
メソッド、またはfinally()
メソッドのいずれかで処理するのが最適です。詳細については、 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
}
);
Promise/A 転送のメカニズムがどのように機能するかを示す簡単な例をいくつか示します。もちろん、これらの例は人為的なものであり、実際の使用では、Promise チェーンは通常、複数の関数呼び出し、さらにはアプリケーション アーキテクチャの複数のレベルにまたがって分散されます。
解決された Promise は、解決値を次の Promise に転送します。最初の Promise である$deferred->promise()
、以下の$deferred->resolve()
に渡される値で解決されます。
then()
を呼び出すたびに、前のハンドラーの戻り値で解決される新しい Promise が返されます。これにより、Promise の「パイプライン」が作成されます。
$ 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"
拒否された Promise は同様に動作し、try/catch も同様に機能します。例外をキャッチすると、それを伝播させるために再スローする必要があります。
同様に、拒否された Promise を処理する場合、拒否を伝播するには、拒否された Promise を返すか、実際にスローすることによって「再スロー」します (Promise はスローされた例外を拒否に変換するため)。
$ 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"
try/catch と同様に、伝播するかどうかを選択できます。解決と拒否を混在させても、ハンドラーの結果は予測可能な方法で転送されます。
$ 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"
このライブラリをインストールする推奨方法は、Composer を使用することです。作曲家は初めてですか?
このプロジェクトは SemVer に続くプロジェクトです。これにより、このブランチからサポートされている最新バージョンがインストールされます。
composer require react/promise:^3.2
バージョンアップの詳細については、CHANGELOG も参照してください。
このプロジェクトはあらゆるプラットフォームで実行することを目的としているため、PHP 拡張機能は必要なく、PHP 7.1 から現在の PHP 8+ での実行をサポートします。このプロジェクトでは、サポートされている最新の PHP バージョンを使用することを強くお勧めします。
当社は長期サポート (LTS) オプションを提供し、スムーズなアップグレード パスを提供することに尽力しています。古い PHP バージョンを使用している場合は、 2.x
ブランチ (PHP 5.4 以降) または1.x
ブランチ (PHP 5.3 以降) を使用できます。どちらも互換性のある API を提供しますが、新しい言語機能は利用できません。次のように、より広範囲の PHP バージョンをサポートするために、同時に複数のバージョンをターゲットにすることができます。
composer require " react/promise:^3 || ^2 || ^1 "
テスト スイートを実行するには、まずこのリポジトリのクローンを作成し、次に Composer を通じてすべての依存関係をインストールする必要があります。
composer install
テスト スイートを実行するには、プロジェクト ルートに移動して次を実行します。
vendor/bin/phpunit
これに加えて、PHPStan を最大レベルで使用して、プロジェクト全体の型安全性を確保します。
vendor/bin/phpstan
Promise は、Brian Cavalier による when.js の移植版です。
また、ドキュメントの大部分は when.js Wiki および API ドキュメントから移植されています。
MITライセンスに基づいてリリースされています。