php-standard-library/default
Provides a DefaultInterface for PHP classes to expose standardized “default” instances. Helps ensure consistent default construction across libraries and apps with a simple, shared contract.
Install the Package:
composer require php-standard-library/default
Ensure your composer.json includes the package under require.
Implement the Interface:
Add DefaultInterface to a class (e.g., User, ApiResponse) and define getDefault():
use PHPStandardLibrary\Default\DefaultInterface;
class User implements DefaultInterface
{
public function getDefault(): static
{
return new static([
'name' => 'Anonymous',
'email' => null,
'active' => false,
]);
}
}
First Use Case: Replace hardcoded or inconsistent defaults with the standardized method:
// Before:
$defaultUser = new User([]);
// After:
$defaultUser = User::getDefault();
Leverage Laravel’s Service Container (Optional): Bind the default instance globally for dependency injection:
// In AppServiceProvider@boot()
$this->app->bind('default.user', fn() => User::getDefault());
Domain Models: Standardize default states for Eloquent models or DTOs:
class Order implements DefaultInterface
{
public function getDefault(): static
{
return new static([
'items' => collect(),
'total' => 0,
'status' => 'pending',
]);
}
}
API Responses: Enforce consistent error/default responses:
class ApiResponse implements DefaultInterface
{
public function getDefault(): static
{
return new static([
'success' => false,
'data' => null,
'errors' => [],
]);
}
}
Service Layer: Provide fallback instances for services:
class PaymentService implements DefaultInterface
{
public function getDefault(): static
{
return new static(app('default.payment-gateway'));
}
}
Testing: Replace mocks with standardized defaults:
// In PHPUnit tests:
$user = User::getDefault(); // Instead of createMock(User::class)
Retrofitting Existing Classes:
Use traits or interfaces to add DefaultInterface without modifying constructors:
trait HasDefault
{
public function getDefault(): static
{
return new static($this->defaultAttributes());
}
protected function defaultAttributes(): array
{
return [];
}
}
Dynamic Defaults via Laravel Bindings: Override defaults per environment or feature flag:
$this->app->when(User::class)
->needs('$default')
->give(fn() => config('app.debug') ? new User(['name' => 'Debug User']) : User::getDefault());
Modular Architecture: Use defaults for plugin compatibility:
// Plugin Defaults
class PluginConfig implements DefaultInterface
{
public function getDefault(): static
{
return new static([
'enabled' => false,
'settings' => [],
]);
}
}
Laravel Facades: Extend facades to use defaults:
// In a custom facade:
public static function defaultUser()
{
return User::getDefault();
}
Form Requests: Set default values in form requests:
public function rules()
{
return [
'user_id' => 'sometimes|exists:users,id,' . User::getDefault()->id,
];
}
Validation: Use defaults in validation rules:
$validator = Validator::make($data, [
'quantity' => 'sometimes|integer|min:1,' . OrderItem::getDefault()->minQuantity,
]);
Events: Dispatch events with default payloads:
event(new OrderCreated(Order::getDefault()));
Circular Dependencies:
Avoid circular references in getDefault() (e.g., User::getDefault() initializing a UserRepository that requires a User).
Fix: Use Laravel’s container to resolve dependencies lazily.
State Contamination:
Shared default instances (e.g., singletons) may retain state across requests.
Fix: Use immutable objects or reset state in getDefault():
public function getDefault(): static
{
return new static($this->defaultAttributes())->resetState();
}
Performance Overhead:
Eager initialization of heavy defaults (e.g., database queries) in getDefault().
Fix: Lazy-load defaults via Laravel’s container:
public function getDefault(): static
{
return $this->app->make(static::class, ['attributes' => $this->defaultAttributes()]);
}
Testing Quirks:
Tests may fail if getDefault() relies on unresolved bindings.
Fix: Mock the container or use a test-specific default:
// In tests:
User::shouldReceive('getDefault')->andReturn(new User(['name' => 'Test User']));
Interface Pollution:
Overusing DefaultInterface can clutter class signatures.
Fix: Use traits or composition for optional defaults:
class User
{
use HasDefault;
}
Default Not Working?:
DefaultInterface.getDefault() (PHP 8+ static return types help catch this).final methods or abstract classes).Container Binding Conflicts: If binding a default globally, ensure it doesn’t override existing instances:
// Bad: Overrides all User instances
$this->app->bind(User::class, fn() => User::getDefault());
// Good: Bind to a specific key
$this->app->bind('default.user', fn() => User::getDefault());
Runtime Errors:
Call to undefined method.
Cause: Forgot to implement getDefault() or the interface.
Fix: Add the missing method or interface.Return type of User::getDefault() must be of type User.
Cause: PHP 8+ static return type mismatch.
Fix: Update the return type hint:
public function getDefault(): User { ... }
Caching Defaults:
Cache getDefault() results to avoid repeated instantiation:
public function getDefault(): static
{
return Cache::remember('default.user', now()->addHour(), fn() => new static($this->defaultAttributes()));
}
Environment-Specific Defaults: Use Laravel’s config to switch defaults:
public function getDefault(): static
{
$attributes = config('app.env') === 'local'
? ['name' => 'Local Dev']
: $this->defaultAttributes();
return new static($attributes);
}
Database-Backed Defaults: For dynamic defaults (e.g., per-tenant), fetch from the database:
public function getDefault(): static
{
return new static(Tenant::query()->defaultUser()->first() ?? $this->defaultAttributes());
}
Custom Default Factories: Create a factory class to generate defaults:
class UserDefaultFactory
{
public function create(): User
{
return User::getDefault()->withRoles(['guest']);
}
}
Default Overrides: Allow runtime overrides via Laravel’s container:
$this->app->when(User::class)
->needs('$defaultOverride')
->give(fn() => $defaultOverride ?? User::getDefault());
Localization: Support language-specific defaults:
public function getDefault(): static
{
$locale = app()->getLocale();
return new static([
'greeting' => trans("defaults.user.greeting.{$locale}"),
]);
}
Plugin System: Let plugins extend or replace defaults:
// Plugin service provider:
$this->app->extend('default.user', fn($default) => $default->mergePluginDefaults());
Event-Based Defaults: Trigger events when defaults are generated:
public function getDefault(): static
{
$instance = new static($this->defaultAttributes());
event(new DefaultGenerated($instance));
return $instance;
}
How can I help you explore Laravel packages today?