Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Result Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require php-standard-library/result
    

    Ensure your project uses PHP 8.1+ (named arguments and union types required).

  2. First Use Case: Replace a simple try-catch block for validation with Result:

    use PHPStandardLibrary\Result\Result;
    
    function validateEmail(string $email): Result {
        return filter_var($email, FILTER_VALIDATE_EMAIL)
            ? Result::ok($email)
            : Result::err("Invalid email format");
    }
    
    $result = validateEmail("invalid@example");
    if ($result->isSuccess()) {
        $email = $result->unwrap(); // "invalid@example"
    } else {
        $error = $result->unwrapErr(); // "Invalid email format"
    }
    
  3. Key Classes to Know:

    • Result::ok($value): Success case.
    • Result::err($error): Failure case.
    • Result::fromCallable($callable): Wrap existing functions/methods.
    • $result->match($success, $failure): Functional-style handling.
  4. Where to Look First:


Implementation Patterns

Usage Patterns

1. Validation Layer

Replace Laravel’s Validator exception-based approach with Result:

use Illuminate\Support\Facades\Validator;

function validateUserInput(array $data): Result {
    $validator = Validator::make($data, [
        'email' => 'required|email',
        'password' => 'required|min:8',
    ]);

    return $validator->fails()
        ? Result::err($validator->errors())
        : Result::ok($data);
}

// Usage in Controller:
$validationResult = validateUserInput($request->all());
$validationResult->match(
    fn($validData) => User::create($validData),
    fn($errors) => response($errors, 422)
);

2. API Response Handling

Map Result directly to Laravel’s Response facade:

use Illuminate\Http\Response;

function getUserOrFail(int $id): Result {
    $user = User::find($id);
    return $user ? Result::ok($user) : Result::err("User not found");
}

// Controller
$response = getUserOrFail($id)->match(
    fn($user) => response($user),
    fn($error) => response(['error' => $error], 404)
);

3. Domain Logic (Pure Functions)

Model business logic as immutable functions returning Result:

function processOrder(Order $order): Result {
    return Result::fromCallable(fn() => $order->charge())
        ->flatMap(fn($payment) => Result::fromCallable(fn() => $order->fulfill()));
}

// Usage
$orderResult = processOrder($order);
$orderResult->match(
    fn($order) => notifyCustomer($order),
    fn($error) => logError($error)
);

4. Async Workflows (Jobs/Queues)

Propagate errors explicitly in Laravel Jobs:

use Illuminate\Bus\Queueable;
use Illuminate\Queue\InteractsWithQueue;

class ProcessPaymentJob implements ShouldQueue {
    use Queueable, InteractsWithQueue;

    public function handle() {
        $result = Result::fromCallable(fn() => $this->chargeCustomer());
        $result->match(
            fn($success) => $this->dispatch([$success]),
            fn($error) => $this->fail($error)
        );
    }
}

5. Middleware

Short-circuit requests with Result:

public function handle(Request $request, Closure $next) {
    $authResult = Result::fromCallable(fn() => Auth::user());
    return $authResult->match(
        fn($user) => $next($request),
        fn($error) => response($error, 401)
    );
}

Workflows

Chaining Operations (flatMap)

Compose multiple Result-returning operations:

function createUserWithProfile(array $data): Result {
    return validateUserInput($data)
        ->flatMap(fn($validData) => Result::fromCallable(fn() => User::create($validData)))
        ->flatMap(fn($user) => Result::fromCallable(fn() => $user->profile()->create($data['profile'])));
}

Error Recovery

Recover from failures gracefully:

function safeOperation(): Result {
    return Result::fromCallable(fn() => riskyOperation())
        ->match(
            fn($result) => Result::ok($result),
            fn($error) => Result::ok(fallbackOperation($error))
        );
}

Testing

Assert Result outcomes in tests:

public function test_validation_fails() {
    $result = validateUserInput(['email' => 'invalid']);
    $this->assertTrue($result->isFailure());
    $this->assertEquals(['email' => ['The email must be a valid email address.']], $result->unwrapErr());
}

Integration Tips

Laravel Service Container

Bind Result adapters for reusable wrappers:

// app/Providers/AppServiceProvider.php
public function register() {
    $this->app->bind(ResultWrapper::class, function () {
        return new ResultWrapper();
    });
}

class ResultWrapper {
    public function safeCall(callable $callable): Result {
        return Result::fromCallable($callable);
    }
}

Custom Error Types

Extend Result with domain-specific errors:

class PaymentFailed extends \RuntimeException {}
class InsufficientFunds extends PaymentFailed {}

function processPayment(): Result {
    return Result::fromCallable(fn() => chargePayment())
        ->mapErr(fn($e) => $e instanceof PaymentFailed ? $e : new PaymentFailed($e->getMessage()));
}

Logging

Log Err variants in middleware:

public function handle($request, Closure $next) {
    $result = Result::fromCallable(fn() => $next($request));
    $result->match(
        fn($response) => $response,
        fn($error) => (new LogError($error))->next($request)
    );
}

class LogError {
    public function __construct(private $error) {}

    public function __invoke($request) {
        \Log::error("Request failed: " . $this->error);
        return response($this->error, 500);
    }
}

HTTP Exceptions

Convert Result::err() to Laravel exceptions where needed:

$validationResult = validateUserInput($data);
if ($validationResult->isFailure()) {
    throw new \Illuminate\Validation\ValidationException($validationResult->unwrapErr());
}

Gotchas and Tips

Pitfalls

  1. Overusing Result for Exceptions:

    • Avoid: Using Result for unrecoverable errors (e.g., DB connection failures).
    • Use: Exceptions for true errors; Result for expected failures (e.g., validation, business logic).
    • Fix: Wrap exception-prone code in Result::fromCallable() only if you handle the error explicitly.
  2. Ignoring Result Values:

    • Avoid: Calling unwrap() on a Result::err() without checks.
      // ❌ Dangerous
      $user = $result->unwrap(); // Throws if $result is Err
      
    • Use: Always check isSuccess() or use match():
      // ✅ Safe
      $user = $result->isSuccess() ? $result->unwrap() : null;
      
  3. Performance in Hot Paths:

    • Avoid: Creating Result objects in tight loops (e.g., bulk operations).
    • Tip: Cache Result instances or use early returns:
      if (!$user) return Result::err("User not found");
      
  4. Type Safety Gaps:

    • Avoid: Generic Err types when domain-specific errors are needed.
      // ❌ Less clear
      Result<string, string> $result;
      
      // ✅ More explicit
      Result<User, ValidationError> $result;
      
    • Fix: Use custom error classes or union types:
      Result<User, ValidationError|PaymentFailed> $result;
      
  5. Middleware/Service Provider Order:

    • Avoid: Assuming Result will propagate through all layers.
    • Tip: Explicitly handle Result in each layer (e.g., middleware, controllers, services).

Debugging

  1. Unwrapping Failures:

    • Use unwrapErr() to inspect errors:
      $error = $result->unwrapErr();
      \Log::error($error);
      
  2. Stack Traces:

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor