Getting started
The CLI
Check, build, and clean a mixed project with predictable selection and machine-readable diagnostics.Two commands do the daily work: check finds problems in your source, and build produces the PHP that runs. Both understand the complete project even when you focus the report or the output on one path.
Command map
| Command | Purpose | Writes generated PHP |
|---|---|---|
ppphp --version |
Print the installed compiler version | No |
ppphp init |
Create the project configuration and generated-code directories | No |
ppphp composer:configure [--dry-run] |
Maintain Composer runtime mapping to generated output | Updates Composer configuration when applied |
ppphp check [path] |
Check selected source with the rest of the project | No |
ppphp build [path] |
Check, compile .ppphp, and copy .php source |
Yes |
ppphp clean [--dry-run] |
Remove generated output and compiler cache paths | Deletes generated files |
Use the Composer-installed executable in project scripts:
vendor/bin/ppphp --version
vendor/bin/ppphp check
vendor/bin/ppphp build
Include the --version output in bug reports so it is clear which compiler produced a diagnostic or build.
Complete-project and focused commands
With no path, check validates every .ppphp and .php file under the configured source roots. A path narrows the diagnostic selection:
vendor/bin/ppphp check src/Checkout
vendor/bin/ppphp check src/Checkout/CheckoutService.ppphp
The compiler still loads valid unselected source, Composer metadata, dependencies, PHPDoc, and configured stubs when they are needed to resolve the selected code. An unrelated invalid file outside the selection does not block a focused command, but a project-wide name conflict can still make the selected target ambiguous.
build follows the same selection model:
vendor/bin/ppphp build
vendor/bin/ppphp build src/Checkout
vendor/bin/ppphp build src/Checkout/CheckoutService.ppphp
vendor/bin/ppphp build src/Legacy/Formatter.php
A complete build writes every file from your configured source directories. Give it a directory to build just that subtree, or a file to build just that file. A .ppphp file is compiled; a .php file is copied byte-for-byte. Related files are checked as needed but are not added to a focused build's output. Run ppphp build without a path for a complete deployable application.
Read a diagnostic
Console diagnostics point at the original .ppphp source. This is the complete output for an assignment that breaks a declared local type:
Error[P2009]: Assignment Is Not Assignable To Declared Type
Value of type string is not assignable to $attempts of type int.
--> src/Attempts.ppphp:6:17
5 | int $attempts = 0;
6 | $attempts = 'three';
| ^^^^^^^ Value of type string is not assignable to $attempts of type int.
7 |
Related: $attempts is declared here.
--> src/Attempts.ppphp:5:5
4 | {
5 | int $attempts = 0;
| ^^^^^^^^^^^^^^^^^^
6 | $attempts = 'three';
Help: Correct the highlighted declaration or expression so it satisfies the stated type contract.
Every diagnostic has the same shape: a severity and code, a title, a one-sentence message, the location as file:line:column, a frame of the source with the problem underlined, any related locations, and a help line. The code is stable across releases, so it is the thing to search for or paste into an issue. The Diagnostics reference lists every code.
Diagnostic families make failures recognizable across CLI, editor, CI, and playground integrations:
| Range | Concern |
|---|---|
P0xxx |
project and configuration |
P1xxx |
syntax |
P2xxx |
variables and strict types |
P3xxx |
generics and typed arrays |
P4xxx |
checked errors |
P5xxx |
when expressions |
P6xxx |
PHP and Composer interoperability |
P7xxx |
emitted PHP |
P9xxx |
guarded compiler failures |
Use JSON in automation
Every project command accepts --format=json:
vendor/bin/ppphp check --format=json
The response has a versioned envelope, source ranges, related labels, help, and a summary:
{
"version": 1,
"diagnostics": [],
"summary": {
"errors": 0,
"warnings": 0,
"notes": 0
}
}
In a CI script or editor integration, read fields such as code, severity, and location from the JSON instead of parsing console text. Paths and ranges refer to your original source, so annotations can link directly to the line you need to fix.
The documented process statuses are useful in CI:
| Exit | Meaning |
|---|---|
0 |
success |
1 |
source diagnostics were reported |
2 |
invalid command, project, or configuration |
3 |
generated output validation failed |
70 |
guarded internal compiler failure |
Common options
Every project command accepts these options:
| Option | Effect |
|---|---|
--working-directory=<path> |
Use another project root instead of the current directory |
--config=<path> |
Read a configuration file other than ppphp.json, relative to the project root |
--format=console\|json |
Choose human-readable or machine-readable diagnostics |
--ansi / --no-ansi |
Force or disable coloured console output; colour is also disabled when NO_COLOR is set |
--debug |
Include internal failure detail in guarded compiler failures |
-n, --no-interaction |
Never prompt; init in particular is safe to script with this flag |
Work with another project root
You do not have to change the process directory:
vendor/bin/ppphp check \
--working-directory=/srv/example \
--config=config/ppphp.json
Relative source selections resolve from the selected project root and must remain beneath a configured source root.
Maintain the runtime mapping
To run the compiled application, Composer must load classes from generated PHP rather than .ppphp source. Use composer:configure to update those paths. Preview the change, apply it, then refresh the lock file and autoloader:
vendor/bin/ppphp composer:configure --dry-run
vendor/bin/ppphp composer:configure
composer update --lock --no-interaction --no-scripts
vendor/bin/ppphp build
composer dump-autoload --optimize
Application entrypoints then load classes and functions from build/ppphp. Source .ppphp files are never executed directly.
See Project configuration for the complete ppphp.json field reference and the contract between runtime mappings and extra.ppphp source metadata.
Clean safely
Preview cleanup before deleting generated files and cached data:
vendor/bin/ppphp clean --dry-run
vendor/bin/ppphp clean
clean validates every target, refuses paths outside the project root, and never deletes a source directory. It does not remove Composer dependencies or application-owned build assets.
Next, read Strict project-wide types to understand what check proves, or Migrating from PHP to plan a gradual migration.