Understand what your Symfony application can actually do — without running it.
PHPFlow is an open-source static flow analyzer for PHP. It reconstructs application paths from HTTP routes and Messenger messages through controllers, handlers, services and repositories, all the way to database effects, external HTTP calls, responses and exceptions.
The graph above uses fictional domain names to keep the example application-neutral. PHPFlow's HTML viewer is self-contained and generated locally from the analyzed source.
When a Symfony application grows, answering a simple question often means jumping through controllers, service interfaces, Messenger configuration, handlers and repositories.
PHPFlow turns that investigation into queries you can repeat:
| Question | PHPFlow |
|---|---|
| What happens when this route is called? | Follow the flow from route to responses, effects and failures. |
| Which entry points touch this table? | Trace database impact backwards to HTTP routes and messages. |
| What depends on this service? | Find the reachable application flows before changing it. |
| Where is this message handled? | Follow Messenger dispatches, handlers and async boundaries. |
| Which flows call this external API? | Find statically recoverable HTTP dependencies and their callers. |
| Where can this exception surface? | Trace failures back to the entry points that can reach them. |
PHPFlow performs static analysis only. It does not boot or execute the target application.
A flow such as:
POST /catalog/{recordId}/sync
└── CatalogController::sync
└── SyncRecord
└── SyncRecordHandler::__invoke
├── RecordRepositoryInterface::findRequired
│ └── RecordRepository::findRequired
│ └── SELECT records
├── ExternalSyncClientInterface::sync
│ └── POST %sync.base_url%/v1/resources
└── RecordLinkRepositoryInterface::insert
└── INSERT record_links
can be explored as an interactive graph with functional lanes, Messenger boundaries, search, filters, minimap navigation, entry-path highlighting, paths to effects and critical-path focus.
The exact graph is deliberately conservative: PHPFlow only reports relationships it can prove from supported static patterns.
The recommended workflow needs only Docker, Docker Compose and GNU Make. PHP does not need to be installed on the host.
After cloning this repository:
cd phpflow
make setupmake setup builds the PHP 8.4 container and installs the locked Composer dependencies.
The fastest way to see PHPFlow working is the bundled Symfony demo:
make demoThis scans the demo and writes the interactive viewer to:
/tmp/phpflow-demo.html
Open that file in a browser. No Symfony server, database, message broker or external API is started: PHPFlow only reads source code and supported configuration.
make scan PROJECT_PATH=/absolute/path/to/projectThen generate its interactive graph:
make export-html \
PROJECT_PATH=/absolute/path/to/project \
HTML_OUTPUT=/tmp/phpflow.htmlPROJECT_PATH is mounted read-only inside the PHPFlow container.
To focus on one route:
make inspect \
PROJECT_PATH=/absolute/path/to/project \
ROUTE='/catalog/{recordId}/sync' \
METHOD=POSTor generate a route-scoped viewer:
make export-html \
PROJECT_PATH=/absolute/path/to/project \
HTML_OUTPUT=/tmp/phpflow-route.html \
ROUTE='/catalog/{recordId}/sync' \
METHOD=POSTThe bundled demo's complete scenario map is documented in
examples/symfony-demo/README.md.
PHPFlow can traverse the graph in the opposite direction too: start with something you plan to change and discover which entry points can reach it.
make impact PROJECT_PATH=/path/to/project TABLE=companies
make impact PROJECT_PATH=/path/to/project HTTP='/v2/directory/search'
make impact PROJECT_PATH=/path/to/project MESSAGE=SyncCompany
make impact PROJECT_PATH=/path/to/project SERVICE='InvoiceGenerator::generate'
make impact PROJECT_PATH=/path/to/project EXCEPTION=PaymentFailedUse SUMMARY=1 when you only need the impacted entry points:
make impact \
PROJECT_PATH=/path/to/project \
SERVICE='InvoiceGenerator::generate' \
SUMMARY=1Database impact can also be narrowed by operation:
make impact-table \
PROJECT_PATH=/path/to/project \
TABLE=companies \
OPERATION=SELECTThe HTML viewer is designed for investigation rather than static diagrams. It includes:
- deterministic hierarchical layout and functional swimlanes;
- distinct async / Messenger boundaries;
- node-type and exploration filters;
- full-graph search across nodes and edge metadata;
- expand/collapse and focused branches;
- entry-point path highlighting;
- path-to-effects and critical-path highlighting;
- a minimap for large graphs;
- detailed node metadata including callable, FQCN and source file when available.
PHPFlow exports versioned JSON for tooling and future CI integrations.
make export-json \
PROJECT_PATH=/path/to/project \
JSON_OUTPUT=/tmp/phpflow.jsonCurrent public schemas:
| Output | Schema |
|---|---|
| Graph JSON | 1.2 |
| Impact JSON | 1.0 |
| Graph diff JSON | 1.0 |
Compare two graph exports:
make diff \
BEFORE=/path/before.json \
AFTER=/path/after.json \
FORMAT=json \
OUTPUT=/tmp/phpflow-diff.jsonA Mermaid exporter is also available for documentation-oriented diagrams.
PHPFlow v0.1 focuses on modern Symfony applications and currently understands, among other patterns:
- PHP declarations, attributes and namespaced symbols;
- Symfony
#[Route]controllers and HTTP responses; - dependency-injected services and interface-to-implementation resolution;
- Symfony service aliases from supported PHP configuration;
- Messenger dispatches, handlers, routing and recursive message flows;
- repositories, Doctrine DBAL calls and QueryBuilder database effects;
- common
SELECT,INSERT,UPDATEandDELETEtable effects; - external HTTP calls with statically recoverable methods and URLs;
- conditions,
match, guards, loops,try/catch/finallyand exceptions; - recursive service/repository chains and cycle detection.
For the precise boundary between supported, partial and not supported, see the v0.1 support matrix.
A missing edge means PHPFlow could not prove that relationship from the supported static patterns. It does not prove that the relationship can never happen at runtime.
PHPFlow is meant to help with codebases that are difficult to understand precisely because their behavior is distributed across framework conventions and configuration.
Static analysis gives it a useful operating model:
- the target application is not executed;
- analysis can work without reproducing a full runtime scenario;
- results can be exported and compared;
- source-level architecture can be investigated before making a change.
This also makes PHPFlow suitable for sensitive or legacy projects where executing arbitrary application code during analysis would be undesirable.
- CLI contract — stable v0.1 commands, exit statuses and output schemas.
- Support matrix — what PHPFlow can and cannot prove today.
- Contributing guide — development workflow and reproducible static-pattern reports.
- Security policy — how to report security-sensitive behavior safely.
- Code of conduct — expectations for project participation.
- Changelog — release history.
- Release checklist — maintainer release procedure.
The recommended repository setup requires Docker with Docker Compose and GNU Make. The PHP package itself requires PHP 8.4.
Install dependencies and run the suite:
make build
docker compose run --rm php composer install
make testVerify the release contract:
make release-check
docker compose run --rm php composer validate --strict
docker compose run --rm php php bin/phpflow --versionPHPFlow is currently evolving around real-world Symfony applications. Reproducible examples of unsupported static patterns are especially useful when reporting issues. See CONTRIBUTING.md before proposing a change or attaching a reproduction.
PHPFlow is released under the MIT License.
