-
-
Save mindplay-dk/6118034336e32376c62c6ca5f28b9470 to your computer and use it in GitHub Desktop.
Declarative service providers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// API: | |
/** | |
* Defines a service instance to be created by calling a constructor. | |
*/ | |
class Service | |
{ | |
public function __construct( | |
/** | |
* @var string $className the class name of the service. | |
*/ | |
public readonly string $className, | |
/** | |
* @var array<string> $params keys of constructor parameter service names or values. | |
*/ | |
public readonly array $params = [] | |
) {} | |
} | |
/** | |
* Defines a service instance to be created by calling a factory method of a service. | |
*/ | |
class Factory | |
{ | |
public function __construct( | |
/** | |
* @var string $key the key of the factory service to call | |
*/ | |
public readonly Closure $factory, | |
/** | |
* @var string $methodName the method name to call on the factory service. | |
*/ | |
public readonly string $methodName, | |
/** | |
* @var array<string> $params keys of method parameter service names or values. | |
*/ | |
public readonly array $params = [] | |
) {} | |
} | |
/** | |
* Defines a service instance as a serializable value. | |
*/ | |
class Value | |
{ | |
public function __construct( | |
/** | |
* @var string|bool|int|float|null|array<string|bool|int|float|null> $value the value to use. | |
*/ | |
public readonly string|bool|int|float|null|array $value | |
) {} | |
} | |
/** | |
* Defines a service as a list of references to other services, factories, values or lists. | |
*/ | |
class Refs | |
{ | |
public function __construct( | |
/** | |
* @var array<Service|Factory|Value|Refs> $items the list of services. | |
*/ | |
public readonly array $items | |
) {} | |
} | |
/** | |
* An extension takes an existing `Service|Factory|Value` definition and returns a replacement. | |
*/ | |
class Extension | |
{ | |
public function __construct( | |
/** | |
* @var Closure(Service|Factory|Value):Service|Factory|Value $extend a function that takes a service and returns a new service. | |
*/ | |
public readonly Closure $extend | |
) {} | |
} | |
interface ServiceProviderInterface | |
{ | |
/** | |
* Returns an array of services to be registered in the container. | |
* | |
* @return array<string, Service|Factory|Value> | |
*/ | |
public function getServices(): array; | |
/** | |
* Returns an array of extensions to be registered in the container. | |
* | |
* @return array<string, Extension> | |
*/ | |
public function getExtensions(): array; | |
} | |
// EXAMPLE: | |
class UserProvider implements ServiceProviderInterface | |
{ | |
public function __construct( | |
private string $cache_path | |
) {} | |
public function getServices(): array | |
{ | |
return [ | |
"cache_path" => Value($this->cache_path), | |
CacheProvider::class => new Service(FileCache::class, ["cache_path"]), | |
UserRepository::class => new Service(UserRepository::class, [CacheProvider::class]), | |
"example" => new Value(1), | |
"loggers" => new Refs([ | |
new Service(Logger1::class), | |
new Service(Logger2::class), | |
]) | |
]; | |
} | |
public function getExtensions(): array | |
{ | |
return [ | |
"example" => new Extension(fn(Value $service) => new Value($service->value + 1)), | |
"loggers" => new Extension(fn(Refs $refs) => new Refs([...$refs->items, new Service(Logger3::class)])) | |
]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment