PHPアプリケーションの成功とエラーの結果に対処するための厳密に型付けられた方法を提供します。
Neverthrowに触発されたので、ここではPHPからのNeverthrowの簡単な実装を行っています。
スローとキャッチングは、GOTOステートメントを使用することと非常によく似ています。それはあなたのプログラムについての推論をより難しくします。第二に、スローを使用することにより、関数の発信者がキャッチを実装していると仮定します。これは既知のエラーソースです。例:1つの開発者がスローし、もう1つの開発者は、関数がスローするという事前知識なしに関数を使用します。したがって、エッジケースは未解決のままにされており、今では不幸なユーザー、ボス、猫などがいます。
とはいえ、プログラムを投入するための良いユースケースが間違いなくあります。しかし、あなたが思っているよりもはるかに少ない。
TL; DR:スローなし=より幸せな生活とアプリケーション。 PHPアプリでは、生産のエラーが少なくなり、ドライと再利用可能なものが増加します。
V2.0.0以降のPHP 8.2+
composer require shipsaas/never-throw NeverThrow\Result 、いつでも拡張する準備ができています。
isOk()isError()getOkResult()getErrorResult() 成功とエラーという2つの新しいクラスを作成します。そして、お気軽にデータを入れてください
use NeverThrow SuccessResult ;
use NeverThrow ErrorResult ;
// Success
class BookShipperOkResult extends SuccessResult
{
public function __construct (
public string $ bookingId
) {}
}
enum BookingErrors {
case NO_SHIPPER_AVAILABLE ;
case OVERWEIGHT_PACKAGE ;
case INVALID_ADDRESS ;
}
// Error
class BookShipperErrorResult extends ErrorResult
{
public function __construct (
public BookingErrors $ outcome
) {}
}ネバースローを使用する前の最後のステップ。専用の結果クラスを作成するのに役立ちます:
use NeverThrow Result ;
class BookShipperResult extends Result
{
public function getOkResult (): BookShipperOkResult
{
return parent :: getOkResult ();
}
public function getErrorResult (): BookShipperErrorResult
{
return parent :: getErrorResult ();
}
} public function createBooking ( User $ user , BookingOrder $ order ): BookShipperResult
{
$ hasAnyShipperAvailable = $ this -> shipperService -> hasAnyShipperAvailable ();
if (! $ hasAnyShipperAvailable ) {
return new BookShipperResult (
new BookShipperErrorResult (
BookingErrors:: NO_SHIPPER_AVAILABLE
)
);
}
$ isOverweight = ! $ this -> weightService -> isValid ( $ order );
if ( $ isOverweight ) {
return new BookShipperResult (
new BookShipperErrorResult (
BookingErrors:: OVERWEIGHT_PACKAGE
)
);
}
$ bookingId = $ this -> book ( $ user , $ order );
return new BookShipperResult ( new BookShipperOkResult ( $ bookingId ));
} $ bookingResult = $ this -> service -> createBooking ( $ user , $ order );
if ( $ bookingResult -> isError ()) {
$ errorResult = $ bookingResult -> getErrorResult ();
// handle error
return showError ( match ( $ errorResult -> outcome ) {
BookingErrors:: NO_SHIPPER_AVAILABLE => ' No shipper available at the moment. Please wait ' ,
BookingErrors:: OVERWEIGHT_PACKAGE => ' Your package is overweight ' ,
});
}
return showBooking ( $ bookingResult -> getOkResult ()-> bookingId );上記のコードでわかるように、次のようになります。
それは開発を本当に素晴らしいものにし、痛みはありません。
厳密にタイプされたリターンタイプを使用すると、開発者は他のサービス/ライブラリで何が起こっているかを知ることができます。したがって、再利用性を向上させます。そして、私たちは私たちのコードを試して、キャッチしてuglifeする必要はありません。
例外を乱用しないでください。予期しない状況(およびエラー!==例外、事実)にのみ使用する必要があります。
function transfer (): Transaction
{
if (! $ hasEnoughBalance ) {
thrown new InsufficientBalanceError ();
}
if (! $ invalidRecipient ) {
throw new InvalidRecipientError ();
}
if (! $ invalidMoney ) {
throw new InvalidTransferMoneyError ();
}
$ transaction = $ this -> transferService -> transfer (...);
if (! $ transaction ) {
throw new TransferFailedError ();
}
return $ transaction ;
}この関数のほとんどは、実際には間違っている可能性のあるものに関するものですが、私たちのタイプは成功したパスを私たちに知らせます。つまり、関数の出力の4/5が型ではないことを意味します!
上記の「例外」または「エラー」は、実際には例外やエラーではありません。それらは結果です。それらは私たちのシステムの予測可能で合理的な部分です。私のヒューリスティックは、彼らが良いプロダクトマネージャーが気にするものであるなら、それらは例外ではなく、あなたはそれらを投げるべきではありません!
例外は、私たちが合理的に計画できない予測不可能なものであり、システムが回復を試みるべきではなく、ユーザーにルーティングすべきではありません。
MITライセンス