Repository navigation
The container stops being a black box. This release adds a first-class introspection API, a PSR-11 bridge, and β finally β containers that actually reload themselves in long-running processes instead of silently serving a stale build forever. A handful of quiet misconfigurations were also promoted to loud errors.
β¨ New Features
- Containers now reload themselves in long-running processes. Until now, auto-rebuild only ever helped the next request: PHP cannot redeclare a class that is already loaded, so a queue worker, a dev server, a CLI tool or an MCP server kept serving the very first compiled container for the rest of its life, no matter how many times the configs changed and the file on disk was regenerated. With auto-rebuild on,
ContainerLoadernow gives every build a fresh class name (Container_<key>_<hash>) and, on everyload(), checks the compiled file's content rather than merely whether it has just been regenerated, so a rebuild done by another process over the same cache (a web request while your worker runs) is picked up as well. A process simply gets a new container instance whenever its configuration changed, with no restart. Without auto-rebuild nothing changes: production still compiles once and never looks back. - New
Container::getServiceDescriptors()β a read-only snapshot of every registered service (name, type, autowiring, tags, aliases, and the instance if it exists), in definition order, without instantiating anything. Tools that until now read the container's private properties throughClosure::bind()and scannedcreateService*methods by reflection can drop the tricks; the Tracy panel already has. - New
Nette\Bridges\DIPsr\PsrContainerβ wrap your container and hand it to any library that speaks PSR-11.get()resolves both service names and autowired types, with ambiguity reported rather than guessed. - A service produced by a factory can autowire itself in its own
setup, so@selfand self-typed arguments work there like anywhere else.
π Bug Fixes
- Windows users: writing the compiled container no longer fails intermittently with "Access is denied" when antivirus or an opcache handle holds the target file for a moment β the rename is briefly retried, and the opcache handle is dropped first. Other platforms behave exactly as before.
addService()refuses a name already taken by a factory, matching the existing behavior for instances. The counterpart:removeService()now removes factories too, so a name freed byremoveService()is genuinely free.
β‘ Performance
- Registering a definition no longer scans every existing definition to check for a case-insensitive name clash; an index does it in constant time. Containers with thousands of services notice.