symfony/options-resolver
Symfony OptionsResolver is array_replace on steroids: define required options, defaults, allowed types/values, normalizers, and validation for robust option/config handling in your PHP code. Great for APIs, components, and reusable libraries.
config/, env(), app() bindings) and service containers, enabling declarative validation for service configurations (e.g., queues, databases, APIs).isset(), is_array()) with declarative schemas, reducing cognitive load and improving maintainability.['database' => ['ssl' => ['cert' => '...']]]) via recursive resolution, critical for Laravel’s multi-layered configs (e.g., config('database.connections.mysql')).$this->app->singleton(OptionsResolver::class, fn() => new OptionsResolver());
config:cache) since resolvers are runtime-evaluated (no static overrides).fn() => env('API_TIMEOUT')), aligning with Laravel’s .env system.laravel/framework, spatie/laravel-package-tools).| Risk Area | Mitigation Strategy |
|---|---|
| PHP Version Mismatch | Target v7.4.x (PHP 8.2+) for broad Laravel compatibility (v10+). Use v8.0.x (PHP 8.4+) for future-proofing. |
| Performance Overhead | Benchmark resolution time for high-traffic services (e.g., API gateways). Expect <1ms for typical configs. |
| Learning Curve | Provide internal docs with Laravel-specific examples (e.g., queue worker configs). |
| Deprecation Breaks | Monitor Symfony’s deprecation cycles (e.g., setDefault() → setOptions()). Plan upgrades 6–12 months ahead. |
| Nested Error Handling | Leverage Symfony’s error paths (e.g., database.ssl.cert) for granular validation feedback in logs. |
Prioritization:
Implementation:
PaymentGatewayResolver)?Migration:
config('old_driver')) should be deprecated first?Monitoring:
Scaling:
array_replace_recursive in config/array.php with OptionsResolver for structured validation.resolve(OptionsResolver::class)).laravel-notification-service) to enforce consistent configs.HttpClient, Messenger) if Laravel uses Symfony components.OptionsResolver (same package, identical API).Phase 1: Pilot Services (2–4 weeks)
// Before
if (!is_numeric($config['timeout'])) {
throw new \InvalidArgumentException('Timeout must be numeric.');
}
// After
$resolver->setAllowedTypes('timeout', ['int', 'null']);
$config = $resolver->resolve($config);
Phase 2: Package Integration (4–6 weeks)
// In a custom package
$resolver = new OptionsResolver();
$resolver->setRequired(['driver']);
$resolver->setAllowedValues('driver', ['mail', 'slack']);
return $resolver->resolve($config);
Phase 3: Global Adoption (6–8 weeks)
config/array.php) with resolvers.config('old_driver')).$resolver->setDeprecated('old_driver', '2.0', 'Use `new_driver` instead.');
Phase 4: Optimization (Ongoing)
| Component | Compatibility Notes |
|---|---|
| Laravel 10+ | Full support (PHP 8.2+). Use v7.4.x of the resolver. |
| Laravel 9.x | Partial support (PHP 8.1+). Use v6.4.x (last LTS). |
| Laravel 8.x | Limited (PHP 7.4+). Use v5.4.x (deprecated). |
| Symfony Components | No conflicts. Same package as Symfony’s OptionsResolver. |
| Custom Packages | Works if packages depend on PHP 8.2+. Use autoloading for resolver classes. |
| Serverless (Bref, etc.) | Supports runtime configs via closures (e.g., fn() => $_ENV['TIMEOUT']). |
Dependency Setup:
composer.json:
"require": {
"symfony/options-resolver": "^7.4"
}
composer update.Resolver Creation:
app/Resolvers/ConfigResolver.php):
use Symfony\Component\OptionsResolver\OptionsResolver;
class ConfigResolver {
public function __construct(private OptionsResolver $resolver) {}
public function resolve(array $config): array {
return $this->resolver->resolve($config);
}
}
Service Integration:
$this->app->singleton(OptionsResolver::class);
$this->app->bind(ConfigResolver::class, fn($app) => new ConfigResolver($app->make(OptionsResolver::class)));
Validation Rules:
PaymentResolver, QueueResolver):
$resolver->setRequired(['api_key', 'timeout'])
->setAllowedTypes('timeout', ['int', 'null'])
->setNormalizer('retries', fn($val) => max(0, $val));
Testing:
PaymentResolverTest).Rollout:
How can I help you explore Laravel packages today?