Last active
February 10, 2021 20:36
-
-
Save stefanofago73/bb888da8e60c2d530e86791eb07bbb09 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php declare(strict_types = 1); | |
/** | |
* NOTE: | |
* | |
* This example is for that legacy code where it's possible to | |
* refactor a sequence of action using a custom DSL. | |
* When not possible to refactor to FP or before using Try-Monad we can | |
* simulate something like a functor... | |
* | |
*/ | |
/** | |
* @template T | |
* | |
* | |
*/ | |
class Result | |
{ | |
/** @var T|null $value */ | |
private $value; | |
/** @var array<\Exception> $exceptions */ | |
private array $exceptions =[]; | |
/** | |
* | |
* @param array<\Exception> $exceptions | |
*/ | |
private function __construct(array $exceptions) | |
{ | |
$this->exceptions=$exceptions; | |
} | |
public final function isError():bool | |
{ | |
return $this->exceptions !== []; | |
} | |
/** | |
* @template R | |
* @param R $value | |
* @return Result<R> | |
*/ | |
public static final function OK($value):Result | |
{ | |
$result = new Result([]); | |
$result->value = $value; | |
return $result; | |
} | |
/** | |
* @template R | |
* @param array<\Exception> $exceptions | |
* @return Result<R> | |
*/ | |
public static final function KO(array $exceptions):Result | |
{ | |
return new Result($exceptions); | |
} | |
} | |
/** | |
* @template U | |
*/ | |
class TryF{ | |
/** @var array<callable> $slots */ | |
private array $slots; | |
private function __construct() | |
{ | |
$this->slots = []; | |
} | |
/** | |
* @template R | |
* @param callable():R $operation | |
* @return TryF<R> | |
*/ | |
public static final function with(callable $operation):TryF | |
{ | |
$instance = new TryF(); | |
$instance-> andThen($operation); | |
return $instance; | |
} | |
/** | |
*@param callable():U $operation | |
*@return TryF<U> | |
*/ | |
public final function andThen(callable $operation):TryF | |
{ | |
$this->slots[]=$this->call($operation); | |
return $this; | |
} | |
/** | |
*@param callable():U $operation | |
*@param Result<U> $fallback | |
*@return TryF<U> | |
*/ | |
public final function andThenOrFallback(callable $operation, Result $fallback):TryF | |
{ | |
$this->slots[]=$this->callWithFallback($operation,$fallback); | |
return $this; | |
} | |
/** @return array<Result<U>> */ | |
public final function result():array | |
{ | |
/** @var array<Result<U>> $data */ $data = []; | |
/** @var callable():Result<U> $calling */ | |
foreach($this->slots as $calling) | |
{ | |
$data[]=$calling(); | |
} | |
return $data; | |
} | |
/** | |
* @param callable():U $operation | |
* @param Result<U> $fallback | |
* @return callable():Result<U> | |
*/ | |
private function callWithFallback(callable $operation, Result $fallback):callable | |
{ | |
return function()use($operation,$fallback):Result{ | |
try{ return Result::OK($operation());}catch(\Exception $exc){ return $fallback; } | |
}; | |
} | |
/** | |
* @param callable():U $operation | |
* @return callable():Result<U> | |
*/ | |
private function call(callable $operation):callable | |
{ | |
return function()use($operation):Result{ | |
try{ return Result::OK($operation());}catch(\Exception $exc){ return Result::KO([$exc]); } | |
}; | |
} | |
} | |
class DTO | |
{ | |
private int $id; | |
public function __construct(int $id) | |
{ | |
$this->id=$id; | |
} | |
public function id():int | |
{ | |
return $this->id; | |
} | |
} | |
$results = TryF::with(fn()=>new DTO(0)) | |
->andThen(fn()=>throw new \Exception("Boooom!!!")) | |
->andThen(fn()=>new DTO(10)) | |
->andThenOrFallback(fn()=>throw new \Exception("KAAAZZZAAAA!!!"),Result::OK(new DTO(5))) | |
->result(); | |
var_export($results); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment