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

Technical Evaluation

Architecture Fit

  • Functional Error Handling Paradigm: The Result type aligns with Laravel’s growing adoption of functional programming patterns (e.g., collect(), tap()), offering a type-safe alternative to exceptions for expected failures. This is particularly valuable in Laravel’s service layer, API responses, and domain logic where explicit error handling improves predictability.
  • Composability with Laravel Ecosystem:
    • Middleware: Enables declarative error handling in middleware pipelines (e.g., Result::match($authResult, ..., fn($err) => abort(401))).
    • Validation: Replaces Validator::fails() with structured Result::Err(ValidationErrors), improving API response consistency.
    • Jobs/Queues: Propagates failures explicitly in async workflows (e.g., Bus::dispatch(new ProcessOrder($order))->then(fn($result) => $result->match(...))).
  • Laravel-Specific Synergies:
    • HTTP Responses: Maps naturally to Laravel’s Response facade (e.g., Result::match(fn($data) => response($data), fn($err) => response($err, 400))).
    • Service Container: Can be bound as a singleton or resolved dynamically for dependency injection.
    • Testing: Simplifies assertions by treating failures as values (e.g., assert($result->isFailure())).

Integration Feasibility

  • Zero Dependencies: Compatible with Laravel’s autoloading (PSR-4) and requires no additional configuration.
  • Backward Compatibility: Non-breaking; can coexist with exceptions via adapters (e.g., Result::fromThrowable()).
  • Low Cognitive Overhead: Familiar to developers experienced with Rust, Scala, or functional programming in PHP (e.g., Either monads).
  • Tooling Support: Works with PHPStan/Psalm for static analysis (e.g., enforcing Result return types).

Technical Risk

  • Cognitive Shift: Requires team buy-in to adopt Result for expected failures (e.g., validation, API responses) instead of exceptions. Mitigation:
    • Gradual Adoption: Start with new features or bounded contexts (e.g., API layers).
    • Documentation: Create a Result usage guide with examples for common Laravel patterns (e.g., validation, HTTP responses).
  • Laravel Ecosystem Gaps:
    • No Native Integration: Laravel’s Validator, Http, and Queue components lack built-in Result support. Workaround: Wrap calls in Result::fromCallable().
    • Logging: Requires custom middleware to log Err variants (e.g., Result::match(..., fn($err) => Log::error($err))).
  • Performance: Minimal overhead, but micro-optimizations may be needed in hot paths (e.g., caching Result::Ok() for idempotent operations).

Key Questions

  1. Use Case Prioritization:
    • Which Laravel layers (API, CLI, Jobs) would benefit most from Result? Example: Replace try-catch in API controllers with Result::match() for HTTP responses.
  2. Error Granularity:
    • Should Err carry domain-specific error types (e.g., PaymentFailed) or remain generic (e.g., string)?
  3. Migration Strategy:
    • How to handle legacy exception-based code? Options:
      • Use Result::fromThrowable() for direct conversion.
      • Create custom adapters (e.g., ValidatorAdapter::validateAsResult()).
  4. Tooling:
    • Can static analysis tools (PHPStan, Psalm) enforce Result usage in specific contexts (e.g., @returns Result<User, ValidationError>)?
  5. Testing Impact:
    • Will Result improve test coverage for edge cases (e.g., Result::err(new RuntimeException()))?
  6. Performance:
    • Are there hot paths where Result overhead (e.g., method calls) is unacceptable? Consider caching or lazy evaluation.

Integration Approach

Stack Fit

  • PHP 8.1+: Leverages named arguments and union types (Result<Model, string>) for type safety.
  • Laravel 10+: Aligns with Laravel’s functional programming trends (e.g., Illuminate\Support\LazyCollection).
  • Complementary Packages:
    • Validation: Replace Validator::fails() with Result::Err() for structured responses.
    • HTTP: Use Result::match() to map Ok/Err to Response objects.
    • Jobs/Queues: Propagate Result through job handling (e.g., Job::handle() => Result::match(...)).
    • Logging: Integrate with Spatie/Laravel-Logging to log Err variants.

Migration Path

  1. Phase 1: Proof of Concept (PoC)
    • Implement Result in a single feature (e.g., API endpoint for user creation).
    • Compare maintainability vs. traditional try-catch.
    • Example:
      // Before
      try {
          $user = User::create($data);
          return response($user);
      } catch (ValidationException $e) {
          return response($e->errors(), 422);
      }
      
      // After
      $result = Result::fromCallable(fn() => User::create($data));
      return $result->match(
          fn($user) => response($user),
          fn($err) => response($err->errors(), 422)
      );
      
  2. Phase 2: Domain-Specific Adoption
    • Apply Result to domains with complex error flows:
      • Validation: Wrap Validator::validate() in Result.
      • External APIs: Use Result::fromCallable() for HTTP clients (e.g., Guzzle).
      • Business Logic: Replace try-catch in services with Result chains.
    • Create a base ResultAwareController trait for consistency.
  3. Phase 3: Infrastructure Layer
    • Wrap Laravel’s exception-prone methods in Result adapters:
      • Database: Result::fromCallable(fn() => Model::findOrFail($id)).
      • Cache: Result::fromCallable(fn() => Cache::get('key')).
      • Mail: Result::fromCallable(fn() => Mail::send($mailable)).
    • Bind Result to the container for dependency injection:
      $this->app->bind(Result::class, fn() => new Result());
      

Compatibility

  • Laravel Facades: Fully compatible; wrap facade calls in Result:
    $userResult = Result::fromCallable(fn() => Auth::user());
    $userResult->match(
        fn($user) => $user->name,
        fn($err) => "Guest"
    );
    
  • Middleware: Use Result to short-circuit requests:
    public function handle($request, Closure $next) {
        $authResult = Result::fromCallable(fn() => Auth::user());
        return $authResult->match(
            fn($user) => $next($request),
            fn($err) => abort(401, $err->getMessage())
        );
    }
    
  • Service Providers: Bind Result to the container for dependency injection:
    $this->app->singleton(Result::class, fn() => new Result());
    

Sequencing

  1. Start with New Code: Avoid modifying legacy exception-heavy codebases initially.
  2. API Layer First: High ROI due to HTTP response consistency.
    • Example: Replace all try-catch in API controllers with Result::match().
  3. Jobs/Queues: Use Result to propagate errors in async workflows:
    Bus::dispatch(new ProcessOrder($order))
        ->then(fn($result) => $result->match(
            fn($order) => Log::info("Order processed"),
            fn($err) => Log::error("Order failed: " . $err)
        ));
    
  4. CLI Artisan Commands: Replace throw new RuntimeException() with return Result::err(new RuntimeException()).
  5. Last: Database Layer: Use Result with Eloquent queries:
    $userResult = Result::fromCallable(fn() => User::where('email', $email)->first());
    

Operational Impact

Maintenance

  • Pros:
    • Explicit Errors: Result forces error handling upfront, reducing runtime surprises (e.g., uncaught exceptions).
    • Immutable State: Easier to debug than mutable objects with side effects.
    • Composable: Simplifies complex workflows (e.g., Result::flatMap() for sequential operations).
    • Testability: Assert failures as values (e.g., assert($result->isFailure())), improving test coverage.
  • Cons:
    • Boilerplate: May increase LOC for simple operations (mitigate with helper methods).
    • Tooling Gaps: Lack
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.
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui