spatie/or-else
Adds an OrElse trait that auto-creates “*OrElse” method variants for your class methods. These variants accept a fallback value that’s returned whenever the original method returns null or false, helping you avoid repetitive default-handling code.
Installation:
composer require spatie/or-else
No configuration is required—just use the trait directly.
First Use Case:
Add the OrElse trait to any class (e.g., a model, service, or DTO) to enable orElse() behavior:
use Spatie\OrElse\OrElse;
class UserService
{
use OrElse;
public function getUser($id)
{
return User::find($id);
}
}
Now call it with a fallback:
$user = app(UserService::class)->getUser(1)->orElse(fn() => User::find(2));
orElse() method’s behavior.find()->orElse(fn() => defaultValue())).Method Chaining with Fallbacks:
Use orElse() to provide a default value or alternative logic when the primary result is null or false:
$result = $this->fetchData()->orElse(fn() => $this->fetchCache());
Integration with Laravel Collections: Combine with collections for fluent fallbacks:
$items = collect($this->getItems())->orElse(fn() => collect([]));
Service Layer Abstraction: Encapsulate fallback logic in services:
class OrderService
{
use OrElse;
public function getOrder($id)
{
return Order::find($id);
}
public function resolveOrder($id)
{
return $this->getOrder($id)->orElse(fn() => $this->createDefaultOrder());
}
}
Closure-Based Fallbacks: Defer expensive operations until needed:
$user = $this->findUser()->orElse(fn() => $this->loadFromExternalApi());
Static Method Usage: Apply to static methods for utility classes:
class StringHelper
{
use OrElse;
public static function getEnv($key)
{
return env($key);
}
}
// Usage:
$value = StringHelper::getEnv('APP_NAME')->orElse('DefaultApp');
Testing: Mock fallbacks in tests:
$this->mock(UserService::class)
->shouldReceive('getUser')
->andReturnNull()
->once();
$result = app(UserService::class)->getUser(999)->orElse(fn() => 'fallback');
$this->assertEquals('fallback', $result);
Null vs. False:
orElse() triggers on both null and false. Use orElseIf() (if available in extensions) for precise control:
// Hypothetical: if the package supported it
$value = $this->getValue()->orElseIf(is_null, fn() => 'null fallback');
Performance: Avoid heavy fallbacks in tight loops. Cache or lazy-load:
// Bad: Expensive fallback in loop
foreach ($ids as $id) {
$this->getData($id)->orElse(fn() => $this->slowOperation());
}
// Good: Pre-compute or use static fallbacks
Trait Conflicts:
If another trait uses the same method name (e.g., orElse), resolve conflicts with:
class MyClass {
use \Spatie\OrElse\OrElse {
orElse as private orElseSpatie;
}
public function orElse($callback) {
return $this->orElseSpatie($callback);
}
}
Check Return Types:
Ensure methods returning null/false are intentional. Use orElse() only for optional values.
// Debug: Log the value before orElse
$value = $this->getValue();
\Log::debug('Value before fallback:', ['value' => $value]);
$result = $value->orElse('fallback');
Closure Scope:
Closures in orElse() inherit the class scope. Access private properties/methods directly:
$user = $this->findUser()->orElse(fn() => $this->createDefault());
Custom Logic:
Extend the trait to add orElseIf or orElseThrow:
trait CustomOrElse {
public function orElseIf($condition, $callback) {
return $this->value === null ? $callback() : $this->value;
}
}
Integration with Laravel:
Combine with optional() for stricter null checks:
$value = optional($this->getValue())->orElse(fn() => 'fallback');
Legacy Code:
Use orElse() to migrate away from ternary checks:
// Before:
$user = $this->findUser() ?: $this->createDefault();
// After:
$user = $this->findUser()->orElse(fn() => $this->createDefault());
How can I help you explore Laravel packages today?