Fournissez un moyen strictement dactylographié de gérer les résultats du succès et des erreurs pour vos applications PHP.
Inspiré par Neverthrow, donc nous voici avec une simple implémentation de Neverthrow de PHP.
Le lancer et la capture sont très similaires à l'utilisation de déclarations GOTO - en d'autres termes; Cela rend le raisonnement sur vos programmes plus difficile. Deuxièmement, en utilisant le lancer, vous supposez que l'appelant de votre fonction implémente les prises. Il s'agit d'une source d'erreurs connue. Exemple: un développement des lancers et un autre Dev utilise la fonction sans savoir préalable que la fonction va lancer. Ainsi, et Edge Case a été laissé non géré et maintenant vous avez des utilisateurs malheureux, des boss, des chats, etc.
Cela dit, il y a certainement de bons cas d'utilisation pour lancer votre programme. Mais beaucoup moins que vous ne le pensez.
Tl; dr: pas de lancer = vie et application plus heureuses. Moins d'erreurs sur la production et augmenter les choses sèches et réutilisables dans vos applications PHP.
PHP 8.2+ depuis v2.0.0
composer require shipsaas/never-throw NeverThrow\Result et prêt à être étendu à tout moment.
isOk()isError()getOkResult()getErrorResult() Nous allons créer deux nouvelles classes: Success & Error. Et n'hésitez pas à mettre l'une de vos données
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
) {}
}Dernière étape avant d'utiliser Neverthrow. La création d'une classe de résultats dédiée nous aide à:
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 );Comme vous pouvez le voir avec le code ci-dessus, il y a:
Cela apporterait le développement vraiment génial et sans douleur.
Avec des types de retour strictement typés, les développeurs peuvent savoir ce qui se passe avec d'autres services / bibliothèques. Ainsi améliore le réutilisable. Et nous n'avons pas à envelopper l'essai / attraper et à uglify notre code.
N'abusez pas d'exceptions, ils ne devraient être utilisés que pour les situations inattendues (et les erreurs! == Exceptions, fait).
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 ;
}La plupart de cette fonction concerne les choses qui peuvent mal tourner, mais nos types nous informent uniquement du chemin réussi. Cela signifie que 4 / 5e de la sortie de la fonction ne sont pas typés !
Les «exceptions» ou les «erreurs» ci-dessus ne sont pas du tout des exceptions ou des erreurs. Ce sont des résultats. Ce sont des parties prévisibles et raisonnables de notre système. Mon heuristique est que s'ils sont quelque chose qu'un bon chef de produit s'en soucierait, ce ne sont pas des exceptions et vous ne devriez pas les jeter!
Les exceptions sont des choses imprévisibles que nous ne pouvons pas raisonnablement planifier, que le système ne devrait pas tenter de récupérer, et nous ne devons pas se rendre à l'utilisateur.
Licence MIT