Skip to documentation

Built-in Providers

FastForward Container provides ready-to-use provider classes to help you register services quickly without building your own provider implementation from scratch.

Overview

Type Responsibility
ArrayServiceProvider Stores factories and extensions in plain arrays
AggregateServiceProvider Merges several providers into one provider object
ServiceProviderContainer Exposes one provider as a PSR-11 container

ArrayServiceProvider

Use this provider when you want the smallest possible amount of ceremony:

use FastForward\Container\ServiceProvider\ArrayServiceProvider;
use FastForward\Container\ServiceProviderContainer;

$provider = new ArrayServiceProvider([
   'foo' => fn() => new FooService(),
   'bar' => fn() => new BarService(),
], [
   'foo' => function ($container, $previous) {
      $previous->setBar($container->get('bar'));
      return $previous;
   },
]);

$container = new ServiceProviderContainer($provider);
$foo = $container->get('foo');

This is the best default for application code, examples, tests, and small libraries.

You can also pass the provider directly to the helper:

use function FastForward\Container\container;

$container = container($provider);
$foo = $container->get('foo');

AggregateServiceProvider

Use this provider when you want to publish or pass around one merged provider:

use FastForward\Container\ServiceProvider\ArrayServiceProvider;
use FastForward\Container\ServiceProvider\AggregateServiceProvider;
use FastForward\Container\ServiceProviderContainer;

$providerA = new ArrayServiceProvider([
   'foo' => fn() => new FooService(),
]);
$providerB = new ArrayServiceProvider([
   'bar' => fn() => new BarService(),
]);

$aggregate = new AggregateServiceProvider($providerA, $providerB);
$container = new ServiceProviderContainer($aggregate);

$foo = $container->get('foo'); // from providerA
$bar = $container->get('bar'); // from providerB

Two details are easy to miss:

  • Factories are merged in provider order, so later providers overwrite earlier keys when the same service ID exists in both.
  • Extensions with the same key are composed in provider order instead of overwritten.

If you want first-match-wins semantics instead of merge semantics, do not aggregate the providers first. Pass them separately to container($providerA, $providerB) .

ServiceProviderContainer

ServiceProviderContainer is the bridge between a service provider and PSR-11 container consumers:

use FastForward\Container\ServiceProviderContainer;

$container = new ServiceProviderContainer($provider);

Important behavior:

  • Resolved entries are cached, including scalar values, arrays, and null .
  • A resolved object is also cached under its final concrete class name when the original ID is different and that class ID has no existing entry or callable definition in the provider container.
  • Extensions may be keyed by the original service ID or by the concrete class name of the resolved service.
  • An ID-based extension can provide an entry without a factory; it receives null as the previous value.
  • Each extension's return value becomes the next value in the resolution chain. Extensions declared void retain the previous value for compatibility.
  • Factories and extensions receive the wrapper container, which defaults to the ServiceProviderContainer instance itself.
Search results