laminas/laminas-servicemanager
Powerful dependency injection and service container for PHP. Manage factories, abstract factories, delegators, aliases, and shared services, with PSR-11 interoperability and robust configuration for complex applications.
Installation:
composer require laminas/laminas-servicemanager
Ensure friendsofphp/proxy-manager-lts is installed for lazy services:
composer require friendsofphp/proxy-manager-lts
Basic Setup:
Create a ServiceManager instance with a minimal configuration:
use Laminas\ServiceManager\ServiceManager;
$serviceManager = new ServiceManager([
'factories' => [
MyService::class => MyServiceFactory::class,
],
]);
First Use Case: Retrieve a service:
$myService = $serviceManager->get(MyService::class);
ConfigAbstractFactory, lazy services).Service Registration:
'factories' => [
MyService::class => MyServiceFactory::class, // Explicit
// OR
MyService::class => ConfigAbstractFactory::class, // Implicit (via config)
],
'factories' => [
MyService::class => InvokableFactory::class,
],
Plugin Managers:
AbstractPluginManager for homogeneous services (e.g., validators, filters).$instanceOf or custom validate() logic.'factories' => [
ValidatorPluginManager::class => function($container) {
return new ValidatorPluginManager($container, [
'factories' => [
StringLengthValidator::class => InvokableFactory::class,
],
]);
},
],
Lazy Services:
LazyServiceFactory as a delegator to defer instantiation:
'delegators' => [
ExpensiveService::class => LazyServiceFactory::class,
],
'lazy_services' => [
'class_map' => [ExpensiveService::class => ExpensiveService::class],
],
Delegators:
'delegators' => [
MyService::class => [
LoggerDelegatorFactory::class,
CacheDelegatorFactory::class,
],
],
Laravel Integration:
Leverage Laravel’s App\ServiceProvider to bootstrap ServiceManager:
public function register()
{
$this->app->singleton('ServiceManager', function ($app) {
return new ServiceManager([
'factories' => [
MyService::class => MyServiceFactory::class,
],
]);
});
}
Configuration:
Use ConfigAbstractFactory to auto-configure services from arrays:
'factories' => [
'config' => ConfigAbstractFactory::class,
],
Then inject config into services:
'services' => [
MyService::class => [
'config' => ['param' => 'value'],
],
],
Testing:
Mock the ServiceManager in tests:
$mockServiceManager = $this->createMock(ServiceManager::class);
$mockServiceManager->method('get')->willReturn(new MyService());
Circular Dependencies:
ServiceManager throws CircularReferenceException if services depend on each other.Plugin Manager Validation:
$instanceOf or override validate() can lead to runtime errors when invalid services are injected.Lazy Service Limitations:
class_map configuration to map service names to classes.LazyServiceFactory fails silently or throws errors.Delegator Order:
Abstract Factory Performance:
vendor/bin/generate-factory-for-class).Service Not Found:
factories, aliases, or delegators.has() to verify service registration:
if (!$serviceManager->has(MyService::class)) {
throw new \RuntimeException("Service not registered!");
}
Factory Errors:
try-catch to provide meaningful errors:
public function __invoke($container, $requestedName, array $options = null) {
try {
return new MyService($options['config']);
} catch (\Exception $e) {
throw new \RuntimeException("Failed to create {$requestedName}: " . $e->getMessage(), 0, $e);
}
}
Lazy Service Debugging:
class_map includes all lazy services:
$serviceManager->get('config')['lazy_services']['class_map'];
Custom Factories:
FactoryInterface for reusable logic:
class MyAbstractFactory implements AbstractFactoryInterface {
public function __invoke(ContainerInterface $container, $requestedName, array $options = null) {
// Shared logic for multiple services
}
}
Custom Delegators:
DelegatorFactory to modify service behavior:
class LoggingDelegatorFactory extends DelegatorFactory {
public function __invoke(ContainerInterface $container, $name, $requestedName, array $options = null) {
$service = parent::__invoke($container, $name, $requestedName, $options);
$logger = $container->get(LoggerInterface::class);
return new LoggingProxy($service, $logger);
}
}
Plugin Manager Extensions:
createService() to add pre/post-processing:
class MyPluginManager extends AbstractPluginManager {
protected function createService($name, $requestedName, $options = null) {
$service = parent::createService($name, $requestedName, $options);
// Modify $service here
return $service;
}
}
Configuration Overrides:
mergeConfig() in ServiceManager to override settings dynamically:
$serviceManager->mergeConfig([
'factories' => [
MyService::class => NewFactory::class,
],
]);
Service Provider Bootstrapping:
Register ServiceManager as a singleton to avoid recreation:
public function register()
{
$this->app->singleton('ServiceManager', function ($app) {
return new ServiceManager($app['config']['services']);
});
}
Service Binding:
Bind Laravel’s container services to ServiceManager for consistency:
$serviceManager->setService('request', $app->make('request'));
Middleware Integration:
Use ServiceManager to resolve middleware in Laravel’s pipeline:
$middleware = $serviceManager->get(Middleware::class);
How can I help you explore Laravel packages today?