Documentation
Installation
Add ++PHP to a Composer project, define the build boundary, and run the first generated PHP.Install the compiler in development and turn expressive .ppphp source into the PHP application you test and deploy. Production consumes the generated PHP, so the operational workflow stays familiar.
Requirements
You need:
- PHP 8.4 or newer to run the compiler
- Composer 2
- a Composer project
- an output directory outside every configured source root
The host PHP version that runs the compiler and targetPhpVersion in ppphp.json are separate choices. The target describes the PHP syntax the generated project may use.
Add the compiler
From the project root, install the canonical package as a development dependency:
composer require --dev atatusoft-ltd/ppphp-src
vendor/bin/ppphp --version
Initialize the project:
vendor/bin/ppphp init
The command creates ppphp.json together with directories for generated PHP, temporary compiler data, and API stubs. It preserves an existing configuration unless you explicitly use --force, and leaves composer.json in your control.
Configure source and output paths
A new project starts with a small configuration:
{
"source": ["src"],
"output": "build/ppphp",
"cache": ".ppphp-cache",
"targetPhpVersion": "8.4",
"stubs": ["stubs"],
"exclude": ["vendor", "build", ".ppphp-cache"]
}
source identifies your source directories. They may contain both .php and .ppphp files. output receives the complete generated PHP tree. cache holds disposable compiler data. stubs describes APIs that must be understood during checks but are not part of the application source.
All configured paths are relative to the project root. Output and cache paths may not overlap a source root, and the compiler rejects unsafe paths instead of risking source data.
Compile one useful file
Create src/Greeting.ppphp:
<?php
namespace App;
final class Greeting
{
public function forName(string $name): string
{
readonly string $prefix = 'Hello';
return $prefix . ', ' . $name;
}
}
Check it without writing production output:
vendor/bin/ppphp check src/Greeting.ppphp
Then build the project:
vendor/bin/ppphp build
The generated class appears at build/ppphp/Greeting.php. The local declaration becomes an ordinary assignment with deterministic PHPDoc, while the namespace, class, method, and expression remain familiar PHP.
Point Composer at generated code
The output tree should be the application tree that Composer loads in environments where ++PHP has been built. For a conventional App\ namespace, the relevant part of composer.json can look like this:
{
"autoload": {
"psr-4": {
"App\\": "build/ppphp/"
}
}
}
After a build, refresh Composer's generated loader:
composer dump-autoload
php -r "require 'vendor/autoload.php'; echo (new App\\Greeting())->forName('Maya');"
A project with a different namespace or several source roots should map each namespace to its corresponding generated path. Do not autoload both the original .ppphp tree and its emitted PHP as competing definitions.
Add the build to your workflow
During development, use a focused check for quick feedback and a complete check before committing. In CI and release builds, run:
vendor/bin/ppphp check --format=json
vendor/bin/ppphp build
composer dump-autoload --classmap-authoritative
vendor/bin/phpunit
A complete build validates the project before replacing the last successful output, validates generated PHP, and never rewrites source files. If compilation fails, treat the output as unavailable for that revision rather than deploying a partial tree.
Common setup problems
“No project configuration was found”
Run the command from the project root or pass --working-directory=/path/to/project. You can also select another file with --config.
A source path is rejected
Keep source, output, cache, and stubs inside the project root. Do not place output or cache inside a source directory, and avoid symbolic-link indirection for generated files and compiler cache paths.
A dependency is unknown during checking
Composer package metadata is read as analysis context. For application-specific dynamic APIs that Composer cannot describe, add a declaration-only stub beneath the configured stubs directory.
Continue with The CLI for selection, diagnostics, and CI behavior, or Mixed projects for a safe file-by-file adoption plan.