Static analysis now types the pillar accessors instead of suppressing them, and the
console gained checks for the mistakes that were previously silent. Both are worth having
before you migrate to 2.0.
Added
gacela initscaffolds a project'sgacela.php— the one file you had to copy from the docs before anything ran. Refuses to overwrite unless--force- PHPStan types
getFacade()/getFactory()/getConfig()from#[ServiceMap]instead of suppressing them. A suppressed call is not a typed one: it evaluated tomixed, which switched off checking of everything reached through the accessor. Nothing to configure beyond the existingphpstan-gacela.neoninclude; the suppression stays as a fallback for classes declaring neither#[ServiceMap]nor a@methoddocblock, and goes away in 2.0 - PHPStan types
getProvidedDependency(Foo::class)asFoo, so the class-string form needs no hand-written@var. String keys staymixed FacadeInterfaceInSyncRulereports public Facade methods missing from the Facade's own*FacadeInterface— drift that is invisible until someone reads both files, by which point the fix is breaking. Only fires for a facade that implements the interface named after itdoctorreports pillar classes whose filename does not match the class. Pillars resolve by filename suffix, so migratingAbstractDependencyProvidermeans renamingDependencyProvider.phptoProvider.phptoo — miss it and the module silently stops resolvingdoctor --strictexits non-zero on warnings as well as errors, so it can gate CIdebug:graph --checkexits non-zero on a module dependency cycle.--allowed-cycles=file.jsonrecords the ones a reviewer accepted, each with a mandatoryreason, and an entry that no longer matches a real cycle fails just as loudly — an allow-list that outlives what it allows is a mute button. Without--checkthe command stays exit-code-neutraldebug:graph --compare-to=base-graph.jsondiffs against a previously captured graph and reports the change as markdown with a mermaid diagram. Writes nothing when the graph is unchanged, so CI can comment only when a pull request actually moves a boundary
Changed
profile:report --format=jsonanddebug:confignow raise aJsonExceptioninstead of printing an empty value when their payload cannot be encodedvalidate:configattributes an unloadable binding class to that binding (Could not resolve binding: <key> (<error>)) instead of reporting a separate "Could not check circular dependencies" linedebug:container <class>no longer prints "Indentation shows dependency depth" — the container returns a flat list, so nothing was ever indented
Documentation
- A Factory can declare its dependencies in its constructor: pillars resolve through the container, so autowiring applies to the Factory itself. This already worked and is now documented and tested
docs/rfc/0002inventories every way to obtain a dependency (25 paths across 4 intents), as the basis for naming one primary path per intent in 2.0