Skip to content

Instantly share code, notes, and snippets.

@ciarand
Last active August 29, 2015 14:04
Show Gist options
  • Save ciarand/16477db954760a4b98d0 to your computer and use it in GitHub Desktop.
Save ciarand/16477db954760a4b98d0 to your computer and use it in GitHub Desktop.
Playing around with creating an intuitive API for Result-type objects (i.e. Failure / Success wrappers) and their interactions w/ Exceptions
<?php
abstract class Result
{
public static function fromValue($value, $reject = null)
{
return ($value !== $reject) ? new Success($value) : new Failure;
}
public static function failOnException($callback)
{
return function ($value) use ($callback) {
try {
return new Success(call_user_func($callback, $value));
} catch (Exception $e) {
return new Failure($e->getMessage());
}
};
}
abstract public function get();
abstract public function failIf($value);
abstract public function resultOf(callable $callable);
abstract public function filter(callable $callable, $message = "");
abstract public function orThrow($type, $message = "");
}
class Success extends Result
{
private $value;
public function __construct($value)
{
$this->value = $value;
}
public function get()
{
return $this->value;
}
public function failIf($value)
{
if ($this->value === $value) {
return new Failure;
}
return $this;
}
public function resultOf(callable $callable)
{
return call_user_func($callable, $this->value);
}
public function filter(callable $filter, $message = "")
{
return call_user_func($filter, $this->value) ? $this : new Failure($message);
}
public function orThrow($type, $message = "")
{
return $this;
}
}
class Failure extends Result
{
private $message;
public function __construct($message = "")
{
$this->message = $message;
}
public function filter(callable $filter, $message = "")
{
return $this;
}
public function failIf($value)
{
return $this;
}
public function resultOf(callable $callable)
{
return $this;
}
public function orThrow($type, $message = "")
{
throw new $type($message ?: $this->message);
}
public function get()
{
throw new RuntimeException("idk");
}
}
/**
* Dummy filters and callables and stuff
*/
class InputIsValidFilter
{
public function __invoke($input)
{
if (intval($input) % 2 === 1) {
return new Success($input);
}
return new Failure("input wasn't odd");
}
}
class Database
{
public static function persist($data)
{
if ($data === 7) {
throw new Exception("some sort of DB error");
}
return $data;
}
}
<?php require "result.php";
return function ($input) {
Result::fromValue($input->whatever)
->failIf("")
->orThrow("InvalidArgumentException", "No data passed")
->resultOf(new InputIsValidFilter)
->orThrow("InvalidArgumentException")
->resultOf(Result::failOnException("Database::persist"))
->orThrow("RuntimeException");
};
<?php
$routine = require "routine.php";
// ////////////////////// //
// boring print utilities //
// ////////////////////// //
$print = function ($attempt, $msg) {
$type = gettype($attempt);
echo "Attempt with {$type} \"{$attempt}\": {$msg}" . PHP_EOL;
};
$printSuccess = function ($attempt) use ($print) {
echo $print($attempt, "succeeded");
};
$printFailure = function ($attempt, Exception $error) use ($print) {
echo $print($attempt, "failed with error {$error->getMessage()}");
};
// ///////// //
// test loop //
// ///////// //
$data = [1, "", 2, 3, 7, "a string", 7 * 3, 211, "whatever"];
foreach ($data as $attempt) {
try {
$routine((object) ["whatever" => $attempt]);
$printSuccess($attempt);
} catch (Exception $e) {
$printFailure($attempt, $e);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment