-
Notifications
You must be signed in to change notification settings - Fork 0
FAQ
Quick answers to questions that came up while writing or reviewing the package. If your question is not here, please open an issue — documentation fixes are reviewed eagerly.
A small, PSR-11 service container that resolves entries on demand and autowires class dependencies via reflection. Typical uses: wiring an application's services at boot, depending on interfaces, and sharing configured singletons across a request or process.
- Per-call instances. Everything resolved is a shared singleton. See Resolution & Caching.
- Contextual / tagged bindings. One identifier maps to one definition.
-
Attribute- or config-driven wiring. Resolution is driven by type hints and
explicit
set()calls only. - Compiled, hot-path containers. Resolution uses runtime reflection without a dumped cache.
See Limitations for the full picture.
Only psr/container ^2.0. Dev
tools (PHPUnit, PHPStan, PHP-CS-Fixer) live under require-dev and are not
installed transitively.
No. If the identifier is an existing class name, the container autowires it without registration. You only register when you need an interface binding, a factory, or to store a value. See Autowiring.
Because 'something' is neither a registered entry nor an existing class name.
That is the PSR-11 contract. Guard optional lookups with has():
if ($container->has('optional')) {
$value = $container->get('optional');
}has() answers it via class_exists(), which does not report interfaces. An
unbound interface is therefore unknown to the container. Bind it first:
$container->set(SomeInterface::class, SomeImplementation::class);See Binding & Factories.
A Closure passed to set() is treated as a lazy factory — it is invoked
with the container on first get(), and its return value is cached. If you want
to store a closure as a plain value, return it from another closure:
$callable = fn () => 'hi';
$container->set('callable', fn () => $callable);
$container->get('callable') === $callable; // trueSee Binding & Factories → Factories.
The container only returns shared singletons. For per-call objects, register a factory object and call its method each time, or construct the object directly:
$container->set(ReportFactory::class);
$report = $container->get(ReportFactory::class)->create(); // fresh each callSee Resolution & Caching.
Re-register it — set() replaces the definition and clears the cached instance:
$container->set(MailerInterface::class, fn () => new InMemoryMailer());Do this before the code under test resolves the service. See Recipes → Swapping a service in a test.
No. The container never invents scalar values. Supply them through a factory or by storing the value and reading it in the factory. See Service Factories.
No — only constructor injection. See Limitations.
It is not autowired (the container can't choose a type). It falls back to the
parameter's default value or null, or fails if neither is available. See
Autowiring → Union and intersection types.
Yes. A cycle (A → B → A, or a class depending on itself) throws
CircularDependencyException instead of
recursing until PHP runs out of memory.
- A missing entry →
NotFoundException(orNotFoundExceptionInterface). - Any build failure →
DependencyIsNotInstantiableException,DependencyHasNoDefaultValueException, orCircularDependencyException. - All of the above at once → the base
ContainerException(orContainerExceptionInterface).
See Exceptions.
A required constructor parameter could not be autowired and had no default or nullable fallback — usually a scalar with no default, or a required, unbound interface. Register the value, add a default, or bind the interface. See Exceptions.
PHP 8.1+, with CI running the suite on 8.1, 8.2, 8.3, and 8.4 against both the lowest and highest dependency versions. See Installation.
max — the strictest level. The source is clean at that level with no baseline
and no ignores.
Under tests/ in the source repo. The suite covers autowiring, value storage,
closures, interface binding, optional/nullable parameters, union types, abstract
and private-constructor classes, circular dependencies, and the has / get /
set contract, at 100% line coverage of the container.
Yes — like every InitPHP package. Breaking changes to the public API (the
Container methods, exception types, PSR-11 behaviour) require a major bump.
Several behaviours were tightened for PSR-11 compliance (lazy set(), throwing
get(), closure factories, corrected exception interfaces). See the
Migration Guide.
See SECURITY.md in
the InitPHP org profile. Please do not file public issues for vulnerabilities.
InitPHP Discussions is the right place for open-ended threads. Concrete bug reports and feature proposals belong in the issue tracker.
initphp/container · MIT License · part of the InitPHP family
Source · Issues · Discussions · Packagist · Contributing · Security Policy
Getting Started
Core Usage
Reference
Practical Guides
Migration & Help