Built-in Factories
What is a Factory?
A factory is the callable responsible for building a service when the container is asked
for it. In this package, all built-in factories implement FactoryInterface
so they can
be used directly inside providers.
Why Use Factories?
Factories allow you to:
- Control exactly how a service is built (constructor, static method, closure, etc.)
- Inject dependencies from the container
- Reuse logic for creating similar services
- Alias or decorate existing services
Quick selection guide
| Factory | Best when | Important behavior |
|---|---|---|
AliasFactory
|
Two IDs should return the same service | Supports cached static helper AliasFactory::get()
|
CallableFactory
|
Construction depends on typed services | Resolves class/interface-typed parameters from the container |
InvokableFactory
|
You want new ClassName(...)
|
Resolves string arguments only when they match existing service IDs |
MethodFactory
|
You need a static or instance factory method | Falls back to new ClassName()
for instance methods when needed |
ServiceFactory
|
You already have the final object | Always returns the same instance |
1. AliasFactory
AliasFactory
makes one service ID behave as an alias for another. When you ask for the
alias, you receive the same object that would be returned for the original ID.
use FastForward\Container\Factory\AliasFactory;
$factory = new AliasFactory('real_service_id');
$service = $factory($container); // Same as $container->get('real_service_id')
If you reuse the same alias in many places, AliasFactory::get('real_service_id')
returns
the same factory instance every time.
2. CallableFactory
CallableFactory
wraps your own callable, but it does not pass raw scalar arguments into
that callable. Instead, it reflects the callable signature and resolves each class- or
interface-typed parameter from the container.
use FastForward\Container\Factory\CallableFactory;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
$factory = new CallableFactory(
static fn(ContainerInterface $container, LoggerInterface $logger): Mailer => new Mailer($logger),
);
If you declare a builtin parameter such as string
or int
, the factory throws
RuntimeException
because builtin types cannot be resolved automatically.
3. InvokableFactory
InvokableFactory
instantiates a class through its constructor.
use FastForward\Container\Factory\InvokableFactory;
$factory = new InvokableFactory(MyService::class, 'my.dependency', 'literal');
$service = $factory($container);
String arguments are treated conservatively:
- if the string matches a registered service ID, it is resolved from the container
- otherwise, it stays a plain literal value
4. MethodFactory
MethodFactory
calls a public static or instance method on a class.
use FastForward\Container\Factory\MethodFactory;
$factory = new MethodFactory(MyService::class, 'build', 'my.dependency');
$service = $factory($container);
Important behavior:
- Static methods are invoked without instantiating the class.
- Instance methods first try
$container->get(MyService::class). - If that lookup fails, the factory falls back to
new MyService(), so the class must be instantiable without constructor arguments in that branch. - Non-public methods trigger
RuntimeException.
5. ServiceFactory
ServiceFactory
wraps a value or object you already created.
use FastForward\Container\Factory\ServiceFactory;
$instance = new MyService();
$factory = new ServiceFactory($instance);
$service = $factory($container); // Always returns $instance
Summary Table
| Factory | Good default for | void when |
|---|---|---|
| AliasFactory | Secondary names and backwards-compatible IDs | You need a different object, not an alias |
| CallableFactory | Typed, custom assembly logic | Your callable needs builtin scalar parameters |
| InvokableFactory | Simple constructor-based services | Construction requires branching logic |
| MethodFactory | Named factory methods or post-construction hooks | The target method is not public |
| ServiceFactory | Existing instances and immutable values | You need a fresh object per resolution |
Tips for Beginners
- If you already have the final object, prefer
ServiceFactorybecause it is the most explicit option. - If you only need constructor calls, start with
InvokableFactory. - If your closure needs services by type, use
CallableFactoryand add proper type hints. - If you need two names for one service, use
AliasFactoryrather than duplicating factory logic. - If a factory method already exists in your domain code,
MethodFactoryusually keeps the documentation easiest to read.