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

Option Laravel Package

php-standard-library/option

Option type for PHP with Some/None to replace nullable values with explicit presence semantics. Helps avoid null checks, clarifies intent, and models optional data safely. Part of PHP Standard Library; see docs and contributing links.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require php-standard-library/option
    

    Add to composer.json if needed:

    "require": {
        "php-standard-library/option": "^6.2"
    }
    
  2. First Use Case Replace a nullable return type with Option in a Laravel service:

    use PhpStandardLibrary\Option;
    
    class UserService {
        public function findByEmail(string $email): Option {
            $user = User::where('email', $email)->first();
            return Option::fromNullable($user);
        }
    }
    
  3. Where to Look First

    • Core Class: vendor/php-standard-library/option/src/Option.php
    • Documentation: PHP Standard Library Docs
    • Laravel Integration: Focus on Option::fromNullable() and Option::some()/Option::none() methods.

Implementation Patterns

Usage Patterns

  1. Replacing Nullable Types Convert ?Type to Option<Type> in method signatures:

    // Before
    public function getUser(): ?User { ... }
    
    // After
    public function getUser(): Option { ... }
    
  2. Functional Chaining Use map, flatMap, and filter for immutable transformations:

    $userOption = $this->userService->findByEmail('test@example.com');
    $emailOption = $userOption->map(fn(User $user) => $user->email);
    
  3. Laravel-Specific Patterns

    • Request Validation:
      $request->validate(['email' => 'required']);
      $user = $this->userService->findByEmail($request->email);
      $user->map(fn(User $user) => $this->sendWelcomeEmail($user));
      
    • Eloquent Relationships:
      $userOption = $this->userService->findById(1);
      $addressOption = $userOption->flatMap(fn(User $user) => Option::fromNullable($user->address));
      
  4. Error Handling Use unwrapOr, unwrapOrElse, or expect for fallback logic:

    $user = $userOption->unwrapOr(User::guest());
    $user = $userOption->unwrapOrElse(fn() => User::create(['email' => 'default@example.com']));
    
  5. Configuration Management Wrap Laravel config values in Option:

    $dbHost = Option::fromNullable(config('database.connections.mysql.host'));
    $dbHost->map(fn($host) => Log::info("DB Host: $host"));
    

Workflows

  1. Domain-Driven Design (DDD) Use Option for entities with optional attributes:

    class Order {
        private Option $shippingAddress;
    
        public function __construct(Option $shippingAddress) {
            $this->shippingAddress = $shippingAddress;
        }
    
        public function getShippingAddress(): Option {
            return $this->shippingAddress;
        }
    }
    
  2. API Layer Explicitly handle missing data in responses:

    $userOption = $this->userService->findById($request->id);
    return response()->json($userOption->map(fn(User $user) => $user->toArray()));
    
  3. Legacy Code Migration Gradually replace null checks with Option:

    // Legacy
    if ($user && $user->address) { ... }
    
    // Refactored
    $userOption = Option::fromNullable($user);
    $addressOption = $userOption->flatMap(fn(User $user) => Option::fromNullable($user->address));
    $addressOption->map(...);
    

Integration Tips

  1. Service Container Bind Option to resolve dependencies:

    $this->app->bind(Option::class, function ($app) {
        return Option::none(); // Default fallback
    });
    
  2. Form Requests Use Option in custom validation rules:

    public function rules(): array {
        return [
            'email' => ['required', new OptionalEmailRule()],
        ];
    }
    
    class OptionalEmailRule implements Rule {
        public function passes($attribute, $value) {
            return Option::fromNullable($value)
                ->filter(fn($email) => filter_var($email, FILTER_VALIDATE_EMAIL))
                ->isSome();
        }
    }
    
  3. Blade Templates Create helpers for Option rendering:

    @php
    function option($option, $callback)
    {
        if ($option->isSome()) {
            echo $callback($option->unwrap());
        }
    }
    @endphp
    
    <!-- Usage -->
    @option($userOption, function ($user) { ... })
    
  4. Testing Assert Option states in PHPUnit:

    $this->assertTrue($userOption->isSome());
    $this->assertEquals('test@example.com', $userOption->unwrap()->email);
    $this->assertTrue($emptyOption->isNone());
    

Gotchas and Tips

Pitfalls

  1. Forgetting to Handle None Always check isSome() or isNone() before unwrapping:

    // Anti-pattern: May throw if $option is None
    $user = $option->unwrap(); // Dangerous!
    
    // Correct
    if ($option->isSome()) {
        $user = $option->unwrap();
    }
    
  2. Overusing Option Avoid Option for trivial cases where null is sufficient:

    // Overkill
    function getSimpleValue(): Option { return Option::some($value); }
    
    // Better
    function getSimpleValue() { return $value; }
    
  3. Performance Overhead Option adds method calls; avoid deep nesting in performance-critical paths:

    // Inefficient
    $result = $option1
        ->flatMap(...)
        ->flatMap(...)
        ->flatMap(...);
    
    // Better: Break into steps
    $step1 = $option1->flatMap(...);
    $step2 = $step1->flatMap(...);
    
  4. Laravel Magic Methods Option may conflict with Laravel’s magic methods (e.g., User::address vs. Option::map):

    // Problematic
    $user->address->map(...); // Calls magic __get(), not Option::map
    
    // Solution
    $addressOption = Option::fromNullable($user->address);
    $addressOption->map(...);
    
  5. Static Analysis Conflicts PHPStan/Psalm may flag Option as unused if not configured:

    # phpstan.neon
    parameters:
        level: 5
        checkMissingIterableMethod: false
        checkMissingProperties: false
    

Debugging Tips

  1. Inspect Option State Use ->isSome()/->isNone() or ->unwrap() in dd():

    dd($option->isSome() ? 'Some' : 'None');
    
  2. Common Errors

    • Cannot call method on None: Use ->map() instead of direct property access.
    • unwrap() on None: Always check isSome() first.
    • Type Mismatch: Ensure Option generic type matches the wrapped value.
  3. Logging Log Option states for debugging:

    Log::debug('User Option:', ['state' => $userOption->isSome() ? 'Some' : 'None']);
    

Configuration Quirks

  1. Autoloading Ensure composer dump-autoload is run after installation:

    composer dump-autoload
    
  2. PHP Version Requires PHP 8.0+ for full match expression support:

    return match ($option->isSome()) {
        true => $option->unwrap(),
        false => null,
    };
    
  3. IDE Support Configure your IDE to recognize Option methods (e.g., in PHPStorm):

    • Add vendor/php-standard-library/option/src to "Sources" in PHPStorm.
    • Use @method annotations for custom classes extending Option.

Extension Points

  1. Custom Option Classes Extend Option for domain-specific behavior:

    class UserOption extends Option {
        public function getEmail(): Option {
            return $this->map(fn(User $user) => $user->email);
        }
    }
    
  2. Integration with Laravel Collections Add Option-aware methods to Laravel’s Collection:

    Collection::macro('toOption', function () {
        return Option::some($this->all());
    });
    
  3. Custom Match Expressions

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.
croct/coding-standard
croct/plug-php
nqxcode/phpmorphy
boundwize/pyrameter
develia/commons
dmstr/symfony-system-resources-bundle
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
renatomarinho/laravel-page-speed
develia/geo-bundle
austinheap/laravel-database-encryption
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
imbo/imbo-coding-standard
visualbuilder/filament-lottie
servicioslineaonce/starter-kit
atomcoder/laravel-reorderable
irajul/filament-shadcn-theme
agtp/agtp-php