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.
Installation
composer require php-standard-library/option
Add to composer.json if using a monorepo or custom package:
"require": {
"php-standard-library/option": "^1.0"
}
First Use Case
Replace a nullable return type with an explicit Option type:
use PhpStandardLibrary\Option;
function findUserById(int $id): Option {
$user = User::query()->find($id);
return Option::some($user) ?? Option::none();
}
// Usage
$userOption = findUserById(1);
if ($userOption->isSome()) {
$user = $userOption->unwrap(); // User object
} else {
// Handle absence explicitly
}
Key Files
src/Option.php (Core class)src/OptionTrait.php (For extending existing classes)Type Safety
Use Option instead of ?Type for:
function getConfigValue(string $key): Option {
return config()->has($key) ? Option::some(config($key)) : Option::none();
}
Method Chaining
Leverage map, filter, and flatMap for functional-style operations:
$result = Option::some($user)
->map(fn($u) => $u->email)
->filter(fn($e) => str_contains($e, '@example.com'));
Integration with Laravel
Option from boot methods:
public function boot(): Option {
return Option::some($this->app->make(SomeService::class));
}
first() with Option:
$user = User::where('active', true)->firstOption();
Custom Collections
Extend Collection to add firstOption():
use PhpStandardLibrary\Option;
class OptionCollection extends Collection {
public function firstOption(): Option {
return $this->isEmpty() ? Option::none() : Option::some($this);
}
}
Null Confusion
Option::none() is not null. Avoid mixing:
// ❌ Anti-pattern
$option = Option::some(null); // Valid but misleading
if ($option->unwrap() === null) { // Unreliable
}
isNone() or unwrapOrDefault().Performance
Option in tight loops may add overhead. Benchmark critical paths.IDE Support
Option types. Use PHPDoc:
/** @return Option<User> */
function findUser(): Option { ... }
$option->isSome(); // bool
$option->isNone(); // bool
$option->unwrapOr($default); // mixed
UnwrapError: Caught via try-catch:
try {
$value = $option->unwrap();
} catch (UnwrapError $e) {
// Handle absence
}
Custom Matching
Extend Option for domain-specific logic:
Option::match(
$option,
fn($value) => "Found: $value",
fn() => "Not found"
);
Interop with Nullables
Convert between Option and ?Type:
$nullable = $option->toNullable(); // ?Type
$option = Option::fromNullable($nullable); // Option<Type>
Laravel-Specific
$value = Option::fromNullable(request()->input('optional_field'));
$option = Option::some($request->input('required_field'))
->filter(fn($v) => strlen($v) > 3);
How can I help you explore Laravel packages today?