Service Factories
A service factory is the object that actually builds a service. It knows the class name, the constructor arguments and any method calls to run after construction, and it turns all of that into a concrete instance when the container asks for it.
This package ships a ready-to-use implementation, ServiceFactory, which implements ServiceFactoryInterface and extends ServiceDefinition. Because of that inheritance a factory is also a full service definition — everything you can do with a definition (for(), fromArray(), arguments(), calls(), the add*Argument helpers) is available on a factory too.
use ClanCats\Container\{
Container,
ServiceFactory
};The factory interface
ServiceFactoryInterface demands a single method: create, which receives the container and returns the built service.
interface ServiceFactoryInterface
{
public function create(Container $container);
}The ServiceFactory::create implementation resolves the constructor arguments, instantiates the class and then applies every registered method call.
Construct your object, or value based on the given container.
Method definition:
public function create(Container $container)Arguments
| Data type | Variable name | Comment |
|---|---|---|
| Container | $container |
Returns
mixed
Constructing a factory
The constructor takes the class name and an optional array of constructor arguments. Prefixing a string with @ marks it as a dependency, : marks a parameter.
$sessionFactory = new ServiceFactory('\\Acme\\Session', ['@session.provider.mysql']);You can keep configuring it using the inherited definition methods:
$engineFactory = ServiceFactory::for(Engine::class)
->calls('setPower', [315]);TIP
Read Service Arguments for the full argument syntax and Service Definitions for every builder method a factory inherits.
Building from an array
Because ServiceFactory extends ServiceDefinition, you can build one from a plain configuration array with fromArray. The class key is required; arguments and calls are optional.
$factory = ServiceFactory::fromArray([
'class' => Car::class,
'arguments' => ['@engine', '@producer'],
'calls' => [
['method' => 'setProducer', 'arguments' => ['@producer']],
],
]);Construct a single service definition object from an array
ServiceDefinition::fromArray([
'class' => '\Acme\Demo',
'arguments' => ['@foo', ':bar'],
'calls' => [
['method' => 'setName', [':demo.name']]
]
])Method definition:
public static function fromArray(array $serviceConfiguration)Arguments
| Data type | Variable name | Comment |
|---|---|---|
| array<mixed> | $serviceConfiguration |
Returns
static
Binding a factory to the container
The most common way to register a factory is through bind, whose third argument decides whether the resulting service is shared (default) or a fresh instance every time.
// shared (singleton) — the default
$container->bind('session', $sessionFactory);
// factory (a new instance on every get) — pass false
$container->bind('engine', $engineFactory, false);If you already have a factory instance and want to be explicit about the sharing behaviour, use the dedicated methods instead of the bind shortcut.
Bind a shared factory
$container->bindFactoryShared('session', $sessionFactory);Binds a shared factory instance to the service container.
Method definition:
public function bindFactoryShared(string $name, $factory)Arguments
| Data type | Variable name | Comment |
|---|---|---|
| string | $name | The service name. |
| ServiceFactoryInterface|Closure | $factory | The service factory instance or closure. |
Returns
void
Bind an unshared factory
$container->bindFactory('engine', $engineFactory);Binds an unshared factory instance to the service container.
Method definition:
public function bindFactory(string $name, $factory)Arguments
| Data type | Variable name | Comment |
|---|---|---|
| string | $name | The service name. |
| ServiceFactoryInterface|Closure | $factory | The service factory instance or closure. |
Returns
void
TIP
For the full picture on the different ways to bind services (class names, closures, factory instances) see Service Binding.
