php-standard-library/result
A lightweight Result type for PHP that represents success or failure as a value, enabling controlled error handling without exceptions. Helps you return, compose, and inspect outcomes explicitly for safer, predictable application flow.
Result type introduces a functional programming paradigm to Laravel’s object-oriented ecosystem, complementing its existing exception-based error handling. It excels in scenarios where expected failures (e.g., validation, API responses, or business logic edge cases) should be treated as values rather than exceptions. This aligns with Laravel’s growing emphasis on composability (e.g., collect(), tap()) and domain-driven design.Result<User, ValidationError>), reducing runtime errors and improving IDE support (autocompletion, type hints). This is particularly valuable in Laravel’s API layers, where HTTP responses must explicitly handle both success and failure states.UserService can return Result<User, Error> instead of throwing exceptions, allowing controllers to handle errors uniformly.Response facade, enabling declarative error responses (e.g., Result::match(fn($data) => response($data), fn($err) => response($err, 422))).Validator::fails() with structured Result::Err(), improving API response consistency.Job::handle() => Result::match(..., fn($err) => $this->fail($err))), enhancing debugging for background tasks.Result-aware middleware to transform Err into HTTP errors or logs).Result.Result::fromThrowable(), allowing gradual migration. For example:
// Convert exceptions to Result
$result = Result::fromThrowable(fn() => User::create($data));
// Service Provider
$this->app->bind(ResultHandler::class, function () {
return new ResultHandler();
});
expectException() with expect(Result::err()), reducing flakiness and improving readability. Example:
$result = $service->process($data);
$this->assertTrue($result->isFailure());
$this->assertInstanceOf(ValidationError::class, $result->unwrapErr());
Result patterns (e.g., map, flatMap, match).Err types may not suffice for complex domains. Mitigation:
Result with domain-specific error types (e.g., Result<Order, PaymentFailed>).interface ApiError).Result instances for repeated operations). Benchmark critical paths post-adoption.Validator, Http, and Queue components lack built-in Result support. Workarounds:
Result::fromCallable() (e.g., Result::fromCallable(fn() => Cache::get($key))).ResultValidator).Err variants (e.g., Result::match(..., fn($err) => Log::error($err))).Bus or Queue may not natively handle Result. Mitigation:
Result::match() in job handlers to propagate errors explicitly.Err into failures (e.g., JobFailed events).Result adoption? Example: Start with API controllers for immediate ROI in response consistency.Result usage in new code without breaking legacy systems? (e.g., PHPDoc @return Result<Type, Error> annotations, static analysis rules).Err use generic types (e.g., string) or domain-specific classes (e.g., ValidationError, PaymentFailed)? Trade-off: specificity vs. boilerplate.Result<Model, Result<ValidationError, DatabaseError>>)? Consider flattening or using Result::flatMap().Result::fromThrowable()).Result converters (e.g., ExceptionToResult::convert($e)).Result be used for all errors or only expected failures? (e.g., use exceptions for E_USER_ERROR but Result for validation).Result usage in specific contexts? Example: Flag methods returning void or mixed without Result.Result-returning methods? (e.g., @method Result<User, ValidationError> create(array $data)).Result improve test coverage for edge cases? Example: Test Result::err() paths alongside Result::ok().Result in unit tests? (e.g., Mockery::mock(Result::class)->shouldReceive('isSuccess')->andReturn(false)).try-catch.Result usage in performance-critical paths? (e.g., caching, lazy evaluation).Result with Laravel’s logging/monitoring (e.g., Sentry, Laravel Telescope)? Example: Log Err payloads with context.Err include stack traces or metadata for debugging? Trade-off: verbosity vs. actionability.function createUser(array $data): Result<User, ValidationError> { ... }
collect(), tap(), LazyCollection). Complements Laravel’s service container, middleware, and HTTP layers.laravel/validation to return Result::Err() for validation failures. Example:
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
return Result::err(new ValidationError($validator->errors()));
}
laravel/framework to map Result to HTTP responses. Example:
$result = $service->process($data);
return $result->match(
fn($data) => response($data),
fn($err) => response($err->toArray(), 422)
);
monolog/monolog for structured logging of Err variants. Example:
$result->match(
fn($data) => Log::info('Success', ['data' => $data]),
fn($err) => Log::error('Failure', ['error' => $err->getMessage()])
);
laravel/queue for explicit error handling in jobs. Example:
public function handle() {
$result = $this->processOrder();
return $result->match(
fn($order) => $this->markAsProcessed($order),
fn($err) => $this->fail($err->getMessage())
);
}
How can I help you explore Laravel packages today?