Proporcione una forma estrictamente escrita para lidiar con los resultados de éxito y error para sus aplicaciones PHP.
Inspirado por NeverThrow, así que aquí estamos con una implementación simple de NeverThrow de PHP.
Lanzar y atrapar es muy similar al uso de declaraciones GOTO, en otras palabras; Hace que el razonamiento sobre sus programas sea más difícil. En segundo lugar, al usar Throw, supone que la persona que llama está implementando captura. Esta es una fuente conocida de errores. Ejemplo: un desarrollo lanza y otro desarrollador usa la función sin conocimiento previo que lanzará la función. Por lo tanto, y el caso de borde se ha dejado sin control y ahora tiene usuarios infelices, jefes, gatos, etc.
Con todo lo dicho, definitivamente hay buenos casos de uso para lanzar su programa. Pero mucho menos de lo que piensas.
TL; DR: Sin Throw = Life y aplicación más felices. Menos errores en la producción y aumentan las cosas secas y reutilizables en sus aplicaciones PHP.
PHP 8.2+ desde v2.0.0
composer require shipsaas/never-throw Class NeverThrow\Result y listo para extenderse en cualquier momento.
isOk()isError()getOkResult()getErrorResult() Crearemos dos nuevas clases: éxito y error. Y no dude en poner cualquiera de sus datos
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
) {}
}Último paso antes de usar NeverThrow. Crear una clase de resultados dedicada nos ayuda a:
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 );Como puede ver con el código anterior, hay:
Traería el desarrollo realmente asombroso y sin dolor.
Con los tipos de devolución estrictamente tipados, los desarrolladores pueden saber qué está sucediendo con otros servicios/bibliotecas. Así hace que el reutilizable sea mejor. Y no tenemos que envolver el try/captación y la actualización de nuestro código.
No abuse de las excepciones, solo deben usarse para las situaciones inesperadas (¡y los errores! == Excepciones, hecho).
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 mayor parte de esta función se trata de las cosas que pueden salir mal, pero nuestros tipos solo nos informan del camino exitoso. ¡Eso significa que 4/5 de la salida de la función no tienen tipo !
Las "excepciones" o "errores" anteriores no son realmente excepciones o errores en absoluto. Son resultados. Son partes predecibles y razonables de nuestro sistema. Mi heurística es que, si son algo que a un buen gerente de producto le importaría, ¡no son excepciones y no debes lanzarlas!
Las excepciones son cosas impredecibles para las que no podemos planificar razonablemente, que el sistema no debe intentar recuperarse, y no debemos enrutar al usuario.
Licencia de MIT