Container
Foundation Container adapts DI52 behind a shared container contract and service provider base class. Use it to describe how application services are constructed while keeping dependency resolution out of the services themselves.
Installation
Section titled “Installation”Install the split package in applications that define their own container or service providers:
Other Foundation packages install Container automatically when they depend on it. Composer does not require a second explicit installation in that case.
Prepare the application
Section titled “Prepare the application”Create one container in the application composition root and register providers in dependency order. These guides establish that structure:
Let the container autowire concrete classes
Section titled “Let the container autowire concrete classes”The container can construct an unbound concrete class when its constructor dependencies are also concrete classes:
Resolve the application entrypoint where it is needed:
Prefer constructor injection throughout application code. Calling get() inside a service hides its dependencies and turns the container into a service locator.
Select an interface implementation
Section titled “Select an interface implementation”In src/Catalog/Provider.php, bind an interface when the container cannot infer which implementation the application wants. Use bind() for a new instance on each resolution and singleton() when every resolution should return the same instance:
Bindings are lazy. Registering Remote_Catalog does not construct it; the container builds it when another service first requests Catalog.
Supply configuration and scalar values
Section titled “Supply configuration and scalar values”In the same src/Catalog/Provider.php, use a contextual binding when one class needs a scalar or a feature-specific implementation. Target scalar constructor arguments by their $name. Import lucatume\DI52\Container as C when a factory callback must resolve another service:
The callback aliases Catalog to the configured Remote_Catalog singleton. This preserves the contextual bindings registered for the concrete class and ensures both identifiers resolve the same object.
Use a factory callback only when the value must be computed or fetched from the container. Let the container construct the complete service whenever it can.
Build a collection across providers
Section titled “Build a collection across providers”In src/Report/Provider.php, use mergeArrayVar() when independent providers contribute to one ordered collection. The provider that owns the collection registers its default and supplies it to the consuming class:
Other feature providers append their implementations without replacing earlier contributions. For example, src/Report/Csv/Provider.php can contribute the CSV implementation:
Register lazy WordPress callbacks
Section titled “Register lazy WordPress callbacks”In src/Catalog/Provider.php, use callback() to let WordPress resolve a service only when its hook runs:
This avoids constructing the synchronizer during every request merely to register its callback.
Decorate a service
Section titled “Decorate a service”In src/Catalog/Provider.php, use a decorator chain when cross-cutting behavior should wrap a service without changing its implementation. List the outermost decorator first and the base implementation last:
Resolving Catalog returns one Logging_Catalog that wraps Caching_Catalog, which wraps Remote_Catalog. Use bindDecorators() instead when the application needs a new chain on every resolution.
Testing
Section titled “Testing”Replace an implementation in a focused test
Section titled “Replace an implementation in a focused test”Bind a test double to the same contract before resolving the class under test:
Test application services through their public behavior. Reserve container integration tests for provider graphs where the binding itself is the behavior under test.