maxiviper117 / result-flow
A minimal Result type with branch-aware chaining for PHP
Fund package maintenance!
Requires
- php: ^8.2
Requires (Dev)
- laravel/pint: ^1.14
- pestphp/pest: ^3.0
- phpbench/phpbench: ^1.4
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: 2.1.37
- rector/rector: 2.3.5
This package is auto-updated.
Last update: 2026-08-10 13:37:16 UTC
README
Minimal, type-safe Result type for explicit success/failure handling in PHP (PHP 8.2+).
Composer:
composer require maxiviper117/result-flow
Documentation map
Why Result Flow
- Explicit branches: success and failure are handled intentionally.
- Metadata propagation: context survives across every chain step.
- Predictable semantics: fail-fast and collect-all tools are explicit and separate.
- Type-aware design: PHPStan-friendly templates across public methods.
Quick example
use Maxiviper117\ResultFlow\Result; $result = Result::ok(['order_id' => 123, 'total' => 42], ['request_id' => 'r-1']) ->ensure(fn (array $order) => $order['total'] > 0, 'Order total must be positive') ->then(fn (array $order) => Result::ok([ 'saved' => true, 'id' => $order['order_id'], ])); $output = $result->match( onSuccess: fn (array $v) => ['ok' => true, 'data' => $v], onFailure: fn ($e) => ['ok' => false, 'error' => (string) $e], );
Deferred operations
use Maxiviper117\ResultFlow\Result; $result = Result::defer(fn () => loadUserById($id)) ->then(fn (array $user) => Result::ok(normalizeUser($user)));
Retry deferred operations
use Maxiviper117\ResultFlow\Result; $result = Result::retryDefer( 3, fn () => callExternalApi($payload), delay: 100, exponential: true, );
Resource-safe operations
use Maxiviper117\ResultFlow\Result; $result = Result::bracket( acquire: fn () => fopen($path, 'r'), use: fn ($handle) => fread($handle, 100), release: fn ($handle) => fclose($handle), );
Batch workflows
Result::mapItems($items, $fn)for per-itemResultstatus.Result::mapAll($items, $fn)for fail-fast aggregate processing.Result::mapCollectErrors($items, $fn)for collect-all error reporting.
All batch callbacks use: fn ($item, $key) => Result|value.
Structured domain errors
For domain-level failures that need a stable API shape and explicit branching, use
subclasses of DataTaggedError and match them by class with matchError(...)
or catchError(...).
use Maxiviper117\ResultFlow\Result; use Maxiviper117\ResultFlow\Support\Errors\DataTaggedError; final class UserPersistError extends DataTaggedError { public const CODE = 'E_USER_PERSIST'; } $result = Result::fail(UserPersistError::from( 'Unable to persist user', ['email' => 'dev@example.com'], )); $message = $result->matchError( [UserPersistError::class => fn (UserPersistError $e) => $e->code()], onSuccess: fn ($value) => 'ok', onUnhandled: fn ($error) => 'unhandled', );
Use code() for boundary serialization and external systems. Matching is based on
the error class, not the string code.
Flows created with of(...), defer(...), retryDefer(...), and batch helpers may widen
failures to TFailure|Throwable; normalize early with catchException(...) / otherwise(...)
when boundary consumers need one stable error shape.
toDebugArray() sanitizes arrays/strings by default. Object internals are only sanitized when
result-flow.debug.sanitize_objects is enabled.
Laravel Boost
This package ships Laravel Boost source assets so AI agents in downstream consumer apps can generate ResultFlow-aware code.
Package-shipped guideline source
- Source file in this package:
resources/boost/guidelines/core.blade.php - In a Laravel app that uses Boost, run:
php artisan boost:install
Boost applies package-shipped guidance within the app AI context.
Package-shipped central skill source
- Source file in this package:
resources/boost/skills/result-flow/SKILL.md
- The central skill loads only needed concept references from:
resources/boost/skills/result-flow/references/*.md
App-level overrides
App teams can define or override guidelines locally:
.ai/guidelines/...
To override a built-in guideline, use the same relative path in .ai/guidelines, for example:
.ai/guidelines/inertia-react/2/forms.blade.php
Contributing
- Tests:
composer test - Static analysis:
composer analyse - Rector check:
composer rector-dry - Rector apply:
composer rector - Format:
composer format - Benchmarks:
composer bench
See CONTRIBUTING.md.
License
MIT - see LICENSE.md.