Architecture
One scan, shared context
Section titled “One scan, shared context”- Discover files. Framework defaults and configuration choose the paths; excluded directories are pruned.
- Parse PHP. Source becomes an abstract syntax tree. No analyzed PHP file is executed by the standalone scanner.
- Collect a semantic index. Track classes, properties, writes and supported container bindings across files.
- Evaluate rules. Local observations and project-level relationships produce findings.
- Apply reporting policy. Suppressions, baselines and the failure threshold determine what is displayed and the exit status.
Performance
Section titled “Performance”- Every file is parsed exactly once. A single AST walk drives semantic indexing, suppression collection and rule dispatch, so adding a rule costs no extra pass.
- Excluded directories are pruned during traversal rather than filtered
afterwards, which is what keeps
vendor/from ever being walked. - Files are read and released one at a time, so peak memory is bounded by the largest single file plus the semantic index, not by the size of the project.
- Rules that need cross-file knowledge emit their findings after the walk, from the shared index — never by re-parsing.
Parallel scanning is not implemented in v1. The architecture allows it: file analysis is independent apart from the shared index.
The replay pipeline (since 1.2.0)
Section titled “The replay pipeline (since 1.2.0)”worker-safety test is a second pipeline, deliberately kept separate from the
static one rather than forced through AnalysisRequest — which carries files,
rules and binding collectors that mean nothing to a black-box HTTP client.
- Load a scenario. YAML, validated as strictly as
worker-safety.yaml: unknown keys are errors, and parsing allows no objects or custom tags. - Send each step in order, over one client, against an already-running application. Order is the whole point — step N runs after step N-1 against the same process.
- Check the response. Status, JSON dot-paths, headers and body substrings, each returning a result rather than throwing, so one run reports every failure instead of stopping at the first.
- Report. Console or JSON, with a schema versioned independently of the scan report.
Two boundaries hold this together:
- Nothing of the target application is loaded. No bootstrap, no autoload, no
container.
testis an HTTP client, the same wayscanis a parser — which is what lets the scanner keep its promise never to execute what it analyzes. - A request that did not complete is not a result. A refused connection, a
stalled body or a response shorter than its
Content-Lengthis a transport error (exit3), never a passed or failed expectation. An assertion can only speak about a response that actually arrived.
See Runtime replay for usage.
Future work
Section titled “Future work”- Symfony-specific rules for container and kernel state.
- Inherited and trait-provided static property analysis.
- Parallel file analysis.
- More
--fix-style guidance, but not automatic code modification.