arielespinoza07 / result-pattern
A modern implementation of the Result pattern for handling operation outcomes in PHP 8.3+
v3.0.0
2026-10-17 00:01 UTC
Requires
- php: ^8.3
Requires (Dev)
- laravel/pint: ^1.27.1
- pestphp/pest: ^4.4.1
- pestphp/pest-plugin-type-coverage: ^4.0.3
- phpstan/phpstan: ^2.1.40
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A modern, immutable implementation of the Result pattern for PHP 8.3+.
Requires PHP 8.3+
Features
- Type-safe result handling with strict type hints and PHPStan level max
- Immutable objects using PHP 8.3+
readonlyclasses - Fluent, chainable API:
map → flatMap → recover → fold - Full generic type inference via
@templateannotations - Comprehensive test suite with Pest PHP and type coverage
Project Structure
src/
├── Result.php # the type: abstract, sealed to Success|Failure, all instance methods
├── Success.php
├── Failure.php
├── Results.php # named constructors and combinators
└── Exceptions/
└── InvalidResultAccessException.php
Result is the type you type-hint. Results is where results come from.
Installation
composer require arielespinoza07/result-pattern
Quick Start
use ArielEspinoza07\ResultPattern\Result; use ArielEspinoza07\ResultPattern\Results; /** @return Result<User, UserNotFound> */ function findUser(int $id): Result { return Results::fromNullable(User::find($id), new UserNotFound($id)); } // Create results $ok = Results::success(42); $err = Results::failure('something went wrong'); // Wrap a throwing operation $result = Results::attempt(fn () => riskyOperation()); // Transform and compose $value = Results::success(2) ->map(fn ($x) => $x * 10) ->flatMap(fn ($x) => Results::success($x + 5)) ->getValueOr(0); // 25 // Handle both branches $output = $result->fold( onSuccess: fn ($v) => "Got: {$v}", onFailure: fn ($e) => "Error: {$e}", );
API Reference
Results: constructors and combinators
| Method | Description |
|---|---|
Results::success($value) |
Wraps a value in a Success |
Results::failure($error) |
Wraps an error in a Failure |
Results::attempt(callable, array $only = []) |
Executes a callable; catches Throwable as Failure. Pass $only to catch only specific exception types. |
Results::fromNullable($value, $error) |
null → Failure($error), non-null → Success($value) |
Results::zip(Result ...$results) |
All succeed → Success([values]), first failure wins (fail-fast) |
Results::collect(array $results) |
Processes all results; returns Failure([errors]) with every error collected (fail-all). Keys are preserved, so errors stay matched to their input |
Result: instance methods
| Method | Description |
|---|---|
isSuccess() |
true if Success; narrows the type for PHPStan |
isFailure() |
true if Failure; narrows the type for PHPStan |
getValue() |
Returns value (throws InvalidResultAccessException on Failure) — prefer getValueOr() |
getError() |
Returns error (throws InvalidResultAccessException on Success) — prefer getErrorOr() |
getValueOr($default) |
Safe value access with fallback (getValueOr(null) for nullable interop) |
getErrorOr($default) |
Safe error access with fallback |
map(callable) |
Transform the value; no-op on Failure |
mapError(callable) |
Transform the error; no-op on Success |
flatMap(callable) |
Chain a Result-returning callable on Success; the error type widens |
recover(callable) |
Convert Failure → Success via fallback value |
recoverWith(callable) |
Convert Failure → Result (recovery can itself fail) |
onSuccess(callable) |
Run a side effect on Success; returns the same result |
onFailure(callable) |
Run a side effect on Failure; returns the same result |
fold(onSuccess, onFailure) |
Collapse both branches into a single value |
Documentation
- Basic Success and Failure Examples
- attempt() Method Examples
- zip() and collect() Examples
- fromNullable() Examples
- onSuccess and onFailure Examples
- Map Method Examples
- mapError() Examples
- FlatMap Method Examples
- Fold Method Examples
- recover() and recoverWith() Examples
- Error Handling Examples
Development
Requirements
- PHP 8.3+
- Composer 2.0+
Setup
git clone https://github.com/ArielEspinoza07/result-pattern.git
cd result-pattern
composer install
Quality Tools
composer check # lint + analyse + test (all-in-one) composer lint # check code style (Pint) composer lint:fix # fix code style composer analyse # static analysis (PHPStan level max) composer test # run tests (Pest PHP) composer test:coverage # type coverage (must stay at 100%)
Contributing
See CONTRIBUTING.md for setup instructions, code conventions, and PR guidelines.