Container Helper Function
The container()
helper is the main entry point for building a fully-featured,
autowire-enabled container in FastForward Container. It is intentionally flexible so
you can start small and add more sources later.
Overview
use function FastForward\Container\container;
$container = container($initializer1, $initializer2, ...);
The helper delegates to ContainerFactory::create()
. You can call the same
composition directly through the static factory:
use FastForward\Container\ContainerFactory;
$container = ContainerFactory::create($initializer1, $initializer2);
Both forms accept the same variadic initializers and create a fresh stack on each call. Existing PSR-11 container objects passed as initializers are reused.
Incremental construction
Use ContainerBuilder
when registration depends on feature flags or occurs
across several setup stages. The factory creates a new builder internally, so
both construction styles use the same assembly implementation.
use FastForward\Container\ContainerBuilder;
$builder = (new ContainerBuilder())->add($config, $baseProvider);
if ($featureEnabled) {
$builder->add($featureProvider);
}
$container = $builder->build();
add()
returns the same builder and accepts the initializers listed below.
Sources are retained in registration order without being instantiated or resolved
during registration. Class strings are instantiated during each build, and
unsupported classes are rejected at that point. Service factories retain their
existing lazy resolution behavior.
The builder is reusable. Each build()
creates fresh aggregate, provider/config
adapters, and autowiring state. Adding sources after a build affects only future
builds. Existing source objects are reused: external PSR-11 containers may still
share their own caches and services across compositions.
The runnable examples/07-incremental-builder.php
demonstrates conditional
registration and the independence of previously built containers.
Supported initializers
| Initializer | Behavior |
|---|---|
ConfigInterface
|
Wrapped in ConfigContainer
|
Psr\Container\ContainerInterface
|
Added directly to the aggregate |
ServiceProviderInterface
|
Wrapped in ServiceProviderContainer
|
string
|
Instantiated with new
and then resolved using the same rules |
All arguments are optional and variadic. You can mix them freely.
How It Works
- Each initializer is resolved to a container instance: - If it's already a container, it's used as-is. - If it's a service provider, it's wrapped in a ServiceProviderContainer. - If it's a config, it's wrapped in a ConfigContainer. - If it's a string, the class is instantiated and then resolved as above. - Unknown class names and unsupported constructed objects throw an InvalidArgumentException.
- All resolved containers are appended to an AggregateContainer.
- If a ConfigContainer is present, it may provide nested initializers, which are also resolved and appended.
- The final result is always an AutowireContainer wrapping the aggregate.
Resolution order
The aggregate container resolves services from left to right. In practice, this means:
- earlier initializers take precedence over later initializers when both can resolve the same ID
- explicit registrations win before autowiring is attempted
- nested and optional object dependencies follow the same source order
container($tests, $defaults)is a simple override pattern for tests and local development
For autowiring alone, new AutowireContainer()
needs no initializers. To extend
one existing PSR-11 container, use new AutowireContainer($existingContainer)
;
its entries are checked before autowiring. See Autowire for both examples.
Examples
Basic usage with a service provider:
use FastForward\Container\ServiceProvider\ArrayServiceProvider;
use function FastForward\Container\container;
$provider = new ArrayServiceProvider([
'foo' => fn() => new FooService(),
]);
$container = container($provider);
$foo = $container->get('foo');
Using a provider class name:
$container = container(MyServiceProvider::class);
Composing multiple providers and containers:
$containerA = container(ProviderA::class);
$containerB = container(ProviderB::class);
$main = container($containerA, $containerB);
Using a config object with nested providers:
use FastForward\Config\ArrayConfig;
use FastForward\Container\ContainerInterface;
use FastForward\Container\ServiceProvider\ArrayServiceProvider;
$config = new ArrayConfig([
'app' => [
'name' => 'FastForward',
],
ContainerInterface::class => [
new ArrayServiceProvider([
Banner::class => static fn($container): Banner => new Banner(
$container->get('config.app.name'),
),
]),
],
]);
$container = container($config);
$banner = $container->get(Banner::class);
Error Handling
Unknown class names and classes that cannot be adapted to a supported container,
provider, or config source raise InvalidArgumentException
. For example,
container(stdClass::class)
and ContainerFactory::create(stdClass::class)
raise this exception before an invalid source reaches the aggregate.
Values outside the public parameter types, such as an array or a direct
stdClass
object, are rejected by PHP with TypeError
.
Failures while expanding optional nested configuration are caught. Expansion stops for that configuration, previously appended sources remain available, and later explicit initializers are still processed.
Configuration note
When you use fast-forward/config
, keep this distinction in mind:
- raw config uses
FastForward\Container\ContainerInterface::classas the key for nested providers - the wrapped
ConfigContainerexposes normal values throughconfig.*IDs
The helper internally asks the ConfigContainer
for
config.FastForward\Container\ContainerInterface
and the config container translates that
into the raw config key for you.
Return Value
The function always returns an AutowireContainer
that wraps an AggregateContainer
composed of all resolved sources. This gives you autowiring and aggregation out of the box,
regardless of how you initialize the container.
Autowiring uses native PHP reflection, resolving optional dependencies before defaults. See Autowire for the resolution rules.