- How do I install Symfony Service Contracts in a Laravel project?
- Use Composer to install it with `composer require symfony/service-contracts`. No additional Laravel-specific configuration is needed, as it integrates directly with PSR-11 containers like Illuminate\Container. The package is framework-agnostic but works out-of-the-box with Laravel’s service container.
- What Laravel versions does Symfony Service Contracts support?
- Symfony Service Contracts is framework-agnostic and works with any Laravel version supporting PHP 8.0+. It doesn’t impose Laravel-specific dependencies, so compatibility depends on your PHP version and PSR-11 container usage. Test thoroughly if using Laravel < 8.0 for edge cases.
- Why should I use Service Contracts instead of Laravel’s built-in interfaces?
- Service Contracts provide standardized, battle-tested abstractions (e.g., `ServiceLocator`, `ContainerProviderInterface`) that reduce custom interface proliferation. They’re ideal for shared libraries or microservices where consistency across Symfony/Laravel ecosystems is critical. Laravel’s native interfaces may suffice for simple apps, but Contracts offer broader interoperability.
- How do I migrate from `ContainerAwareInterface` to `ContainerProviderInterface` in Laravel?
- Replace `ContainerAwareInterface` with `ContainerProviderInterface` in your service classes. Update type hints, IDE autocompletion, and any custom implementations. Laravel’s `Illuminate\Container\Container` already supports `ContainerProviderInterface`, so no container-level changes are needed. Run `php artisan optimize:clear` afterward to refresh cached bindings.
- Can I use Service Contracts for Laravel Jobs or Commands?
- Yes. Use `ServiceLocator` for lazy-loading services in Jobs/Commands (e.g., injecting dependencies via `get()` calls). For declarative subscriptions, implement `ServiceSubscriberInterface` to register services dynamically. This avoids hard dependencies and improves testability by mocking the locator instead of concrete services.
- Will Symfony Service Contracts break my existing Laravel service providers?
- No, unless your providers extend or implement `ContainerAwareInterface`. If they do, migrate to `ContainerProviderInterface` as described above. The package doesn’t modify Laravel’s service container behavior—it only adds standardized interfaces for optional use. Always test after updates to confirm compatibility.
- How do I test services using Symfony Service Contracts in Laravel?
- Mock `ServiceLocator` or `ContainerProviderInterface` in your tests to isolate dependencies. For example, use PHPUnit’s mock builder to stub `get()` calls or verify service subscriptions. Laravel’s `Mockery` or `PHPUnit` can handle this seamlessly. Focus on testing contract compliance rather than concrete implementations.
- Are there performance implications for using Service Contracts in production?
- Minimal. The overhead is negligible for basic usage, as Contracts are just interfaces with no runtime logic. However, lazy-loading via `ServiceLocator` may introduce slight delays if services aren’t pre-bound. Profile with Laravel’s `tideways/xhprof` or `spatie/laravel-profiler` to validate. For performance-critical paths, pre-bind services in providers.
- What alternatives exist to Symfony Service Contracts for Laravel?
- For Laravel-specific solutions, consider `illuminate/contracts` (Laravel’s native interfaces) or `league/container` for PSR-11 compliance. For broader PHP interoperability, `php-di/php-di` or `symfony/dependency-injection` offer DI containers with contracts. However, Symfony Service Contracts is the most widely adopted choice for Symfony/Laravel interoperability.
- How do I handle missing services in `ServiceLocator` without throwing `ServiceNotFoundException`?
- Catch `ServiceNotFoundException` and return a fallback (e.g., a null object or default value). Alternatively, implement custom logic in your service class to handle missing dependencies gracefully. For example, wrap `locator->get()` in a try-catch block or use a decorator pattern to provide defaults. This aligns with Symfony’s error-handling best practices.