Coder Social home page Coder Social logo

php-try's Introduction

Php Try type

A Try type for PHP.

The Try type is useful when called code will either return a value (Success) or throw an exception (Failure). Instead of relying on the try {} catch {} mechanism to handle this cases, the fact that code might either throw or return a value is now encoded in its return type.

The type shows it usefulness with it's ability to create a "pipeline" operations, catching exceptions along the way.

Note: this implementation of the Try type is called Attempt, because "try" is a reserved keyword in PHP.

Before / after

Before, the UserService and Serializer code might throw exceptions, so we have an explicit try/catch:

try {
    $user = $userService->findBy($id);
    $responseBody = $this->serializeUser($user);

    return new Response($user);
} catch (Exception $ex) {
    return Response('error', 500);
}

After, the UserService and Serializer now return a response of type Try meaning that the computation will either be a Failure or a Success. The combinators on the Try type are used to chain the following code in the case the previous operation was successful.

return $userService->findBy($id)
    ->flatMap(function($user) { return $this->serializeUser($user); }) // walk the happy path!
    ->map(function($responseBody) { return new Response($responseBody); })
    ->recover(function($ex) { return new Response('error', 500); })
    ->get(); // returns the wrapped value

Installation

Run:

composer require phptry/phptry

or add it to your composer.json file.

Usage

Note: most of the example code below can be tried out with the user-input.php example from the examples/ directory.

Constructing an Attempt

Turn any callable in an Attempt using the Attempt::call() construct it.

\PhpTry\Attempt::call('callableThatMightThrow', array('argument1', 'argument2'));

Or use Success and Failure directly in your API instead of throwing exceptions:

function divide($dividend, $divisor) {
    if ($divisor === 0) {
        return new \PhpTry\Failure(new InvalidArgumentException('Divisor cannot be 0.'));
    }

    return new \PhpTry\Success($dividend / $divisor);
}

Using combinators on an Attempt

Now that we have the Attempt object we can use it's combinators to handle the success and failure cases.

Getting the value

Gets the value from Success, or throws the original exception if it was a Failure.

$try->get();

Falling back to a default value if Failure

Gets the value from Success, or get a provided alternative if the computation failed.

// or a provided fallback value
$try->getOrElse(-1);

// or a value returned by the callable
// note: if the provided callable throws, this exception will not be catched
$try->getOrCall(function() { return -1; });

// or else return another Attempt
$try->orElse(Attempt::call('divide', array(42, 21)));

// or else return Another attempt from a callable
$try->orElseCall('promptDivide');

Walking the happy path

Sometimes you care about the Success path and want to propagate or even ignore Failure. The filter, flatMap and map operators shown below will execute the given code if the previous computation was a Success, or propagate the Failure otherwise. If the function passed to flatMap or map throws, the operation will result in a Failure.

// map to Another attempt
$try->flatMap(function($elem) {
    return Attempt::call('divide', array($elem, promptDivide()->get()));
});

// map the success value to another value
$try->map(function($elem) { return $elem * 2; });

// Success, if the predicate holds for the Success value, Failure otherwise
$try->filter(function($elem) { return $elem === 42; })

// only foreachable if success
foreach ($try as $result) {
    echo $result;
}

Recovering from failure

When we do care about the Failure path we might want to try and fix things. The recover and recoverWith operations are for Failure, what flatMap and map are for Success.

// recover with with a value returned by a callable
$try->recover(function($ex) { if ($ex instanceof RuntimeException) { return 21; } throw $ex; })

// recover with with an attempt returned by a callable
$try->recoverWith(function() { return promptDivide(); })

The recover and recoverWith combinators can be useful when calling for example http services that might fail. A failed call can be recovered by calling the service again or calling an alternative service.

Don't call us, we'll call you

The Try type can also call provided callables on a successful or failed computation:

// on* handlers
$try
    ->onSuccess(function($elem) { echo "Result of a / b * c is: $elem\n"; })
    ->onFailure(function($elem) { echo "Something went wrong: " . $elem->getMessage() . "\n"; promptDivide(); })
;

Lazily executed Attempts

It is possible to execute the provided callable only when needed. This is especially useful when recovering with for example expensive alternatives.

$try->orElse(Attempt::lazily('someExpensiveComputationThatMightThrow'));

Other options

When you have phpoption/phpoption installed, the Attempt can be converted to an Option. In this mapping a Succes maps to Some and a Failure maps to a None value.

$try->toOption(); // Some(value) or None()

Inspiration

  • Implementation and general idea is based on scala's Try
  • Schmittjoh's Option type for PHP

php-try's People

Contributors

asm89 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.