Last updated: May 2026. Edit this file when milestones change; keep in sync with issue #78, #1044 (North Star 1), #1056 (North Star 2), and the README.
php-compiler is a PHP compiler that:
lib/Compiler.php)phpc run, bin/vm.php)lib/JIT.php)phpc build, bin/compile.php)Deployed apps can run without Zend PHP at runtime. Development and bootstrap still use system PHP today.
This document is the public development status for the project. Technical contributor docs (inventory, capabilities matrices, CI matrices) stay in the repository docs/ tree and are not mirrored on this site.
Indicative composite toward a web-capable, self-hosting compiler (not line-count parity with Zend PHP):
| Area | Progress | Summary |
|---|---|---|
| Foundation (CI, CLI, Docker) | ~88% | phpc CLI, local/Docker CI, bootstrap GHA workflow |
| Language (OOP, types, CFG) | ~62% | VM/JIT OOP largely works; gaps in typed arrays, ::class, some returns |
| Stdlib | ~55% | Large batches of JIT builtins; many functions VM-only |
| Web AOT (build, deploy) | ~65% | Project link β ; home-route execute β ; PATH_INFO / layout chain π§ |
| Reference app (MiniWebApp) | ~55% | VM β ; AOT link β ; AOT execute partial |
| Self-host bootstrap | ~35% | M0 β ; M1 π§; full self-compile M5 β¬ (#1056) |
Overall (indicative): ~45% toward the stated north stars below.
For per-function truth, see the generated capabilities matrix in the repo.
Work is prioritized along two parallel tracks:
Living tracker: #1044 Β· Roadmap: #78 Β· Gate ladder: #472
Compile and run a normal small PHP web application end-to-end without Zend PHP at runtime:
public/index.php, classes, config.php, templates)$_GET, $_POST, $_SERVER, β¦) for request dispatchinclude / partials (not a single echo script)phpc build --project β native binary; phpc deploy β dist tree for CGI/FastCGI (#609, #718).phpc/bin/app output matches phpc serve / VM for the reference route matrixThis is North Star 1. It is orthogonal to North Star 2 (self-host) β the compiler compiling its own lib/ tree.
003-MiniWebAppCanonical app: examples/003-MiniWebApp Β· scaffold: phpc init --profile miniwebapp
| Route | Method | Behavior |
|---|---|---|
/ or /index.php |
GET | Home page (layout + config) |
/index.php/hello?name= |
GET | Greeting |
/index.php/contact |
POST | Form thank-you |
/index.php/api/status |
GET | JSON status |
?route=β¦ |
GET/POST | Legacy query dispatch (still supported) |
Layout: phpc.json manifest, public/index.php (PATH_INFO + query fallback), src/Router.php, templates/ (runtime includes), assets/style.css.
| Layer | Status | Notes |
|---|---|---|
Lint (phpc lint --all) |
β | Class methods, includes, superglobals (#539) |
| VM serve | β | phpc serve + PATH_INFO curls (#489) |
| VM CLI matrix | β | MiniWebApp*VmCli in ci-fast.sh (#597) |
| Web shell smoke | β | examples-web-smoke.sh (#664) |
| AOT link | β | phpc build --project (#752) |
| AOT execute | π§ partial | Home ?route=home β
(#764 closed, #1040); hello / contact / PATH_INFO / layout chain still open |
| AOT HTTP / deploy 003 | β¬ | Blocked on execute matrix (#676, #833, #612) |
Examples 000β002 and 004 already pass VM + AOT link + AOT execute. 003 is the integration stress test for real web apps.
Run ./script/miniwebapp-gates.sh or phpc doctor --gates. Details: miniwebapp-gates.md (repo only).
| Stage | Check | Default on master |
|---|---|---|
| 1 | Lint green | β |
| 1b | VM CLI route matrix | β |
| 2 | PHPUnit ServeTest @miniwebapp |
β |
| 3 | Examples web-smoke (curl) | β |
| 4a | AOT dry-run lint | probe |
| 4b | AOT link | β |
| 4b2 | AOT execute (PHPUnit) | opt-in MINIWEBAPP_AOT_EXECUTE_GATE=1 (#791) |
| 4c | examples-aot-smoke 003 slice |
β (#881) |
| 4d | Deploy smoke (003) | 001/002 only (#718) |
Smallest reproducers first β see #78 bisect table:
| Step | Issue | Focus |
|---|---|---|
| β | #848, #806 | isset / require_return |
| π§ | #878 | Nested two-tier includes |
| π§ | #867 | miniwebapp_render_home phpt |
| π§ | #866 | $_SERVER in included layout.php |
| π§ | #846, #831, #832 | Layout partials, contact, private methods |
| π§ | #849 | JSON api/status in class method |
| π§ | #784, #807 | Title-branch partial includes |
DevEx: #879 miniwebapp-aot-bisect.sh, #880 @group miniwebapp-bisect.
./phpc lint --all examples/003-MiniWebApp
./phpc serve examples/003-MiniWebApp
cd examples/003-MiniWebApp && ../../phpc build --project .
QUERY_STRING=route=home REQUEST_METHOD=GET ./.phpc/bin/app | wc -c # expect non-zero
make miniwebapp-gates
MINIWEBAPP_AOT_EXECUTE_GATE=1 ./script/ci-local.sh --filter MiniWebAppAotExecuteTest
Living tracker: #1056 Β· Roadmap: #78 Β· Process: #1025
The compiler fully compiles itself β the stretch goal behind every bootstrap milestone:
phpc / compiler binary built from php-compiler lib/ + policy-selected ext/ (no vendor/)bin/compile.php / bin/vm.php driver paths (not stub-only echo demos)examples/000-HelloWorld without Zendbin/vm.php inventory (~413 files), with PHP_COMPILER_SELFHOST_AOT stub surface shrinking as lowering landsThis is North Star 2. It is orthogonal to North Star 1 (web app) β user-facing web apps vs. the compiler eating its own lib/ tree.
Not required for M5 close: in-process LLVM linker (lib/AOT/Linker.php may keep external clang); 100% Zend parity; replacing North Star 1.
Zend PHP still runs bin/compile.php during bootstrap. The output is a curated, stub-tolerant native bundle (test/selfhost/compiler_minimal/) β not yet a replacement for system PHP. With PHP_COMPILER_SELFHOST_AOT=1, many Compiler / JIT / VM paths use LLVM stubs so the bundle links; SelfHostBuiltinPolicy keeps ~40 stdlib builtins at real lowering and stubs the rest.
docs/bootstrap-selfhost.md (repo only)docs/bootstrap-inventory.md (php script/bootstrap-inventory.php)| Milestone | Meaning | Status |
|---|---|---|
| M0 β Bundled subset runs | ~109 literal require_once units in test/selfhost/compiler_minimal/main.php β build/selfhost prints compiler_minimal bundle OK |
β #557, #913 |
| M1 β Compiler-shaped bundle | Bundled Compiler.php AOT lint; compile-smoke native link + AOT echo (compiler smoke); driver smoke toward bin/compile.php |
π§ #1025 |
M2 β Full top-level lib/ |
All 14 top-level lib/*.php in one honest bundle; bundle grows toward bin/vm.php spine |
π§ lint β ; link/run open |
| M3 β Native compiles PHP | Self-hosted binary compiles + runs examples/000-HelloWorld without Zend |
β¬ |
| M4 β Bootstrap loop | Native toolchain rebuilds the next compiler sources (same tree, new revision) | β¬ |
| M5 β Full self-host | Real bin/vm.php / bin/compile.php path on full inventory; no Zend bootstrap |
β¬ north star (#1056) |
| Set | ~Files | Notes |
|---|---|---|
compiler_minimal bundle today |
109 | Literal require_once closure |
bin/vm.php inventory target |
413 | Full compiler spine |
Top-level lib/*.php |
14 | Per-file AOT lint β |
| Phase | Command / doc | Status |
|---|---|---|
| A β Inventory | php script/bootstrap-inventory.php --check |
β ~413 files; 0 source blockers |
| B β AOT lint | lib/*.php, test/bootstrap-aot/, selfhost bundles |
β |
| C β Native fixtures | make bootstrap-aot-link |
β |
D β lib/ in bundle |
lib/OpCode.php etc. |
β #540 |
| E β Waves | ./script/bootstrap-wave-check.sh |
π§ NEXT_LOWER probes |
| Gate | Command | Status |
|---|---|---|
| Inventory | php script/bootstrap-inventory.php --check |
β M0+ |
| Lib AOT lint | php bin/compile.php -l lib/*.php |
β
14/14 top-level lib/*.php |
| Bundled compiler lint | ./script/bootstrap-selfhost-lint.sh |
β M0 |
| Native link + run | ./script/bootstrap-selfhost-link.sh |
β M0 |
| Compile smoke link | make bootstrap-selfhost-compile-smoke |
β M1 |
| Compile smoke AOT echo | make bootstrap-selfhost-compile-smoke-run |
β M1 partial |
| Wave gate | ./script/bootstrap-wave-check.sh |
β CI / GHA |
| Next includes probe | php script/bootstrap-selfhost-next-includes.php |
π§ bundle growth |
make bootstrap-wave-check
./script/bootstrap-selfhost-link.sh
make bootstrap-selfhost-compile-smoke-run
php script/bootstrap-selfhost-next-includes.php
| Area | Issues |
|---|---|
| Class methods / JIT objects | #58, #145, #828 |
| Namespaces + bundle growth | #84 |
| Try/catch unwind | #57 |
| Parser / vendor strategy | php-cfg, php-types, php-llvm β M5 approach TBD |
| External linker | lib/AOT/Linker.php excluded from bundle (shell_exec) |
GitHub issues use labels phase-0:Foundation β¦ phase-5:reference-app. Delivery order:
| Phase | Focus | Representative status |
|---|---|---|
| 0 β Foundation | CI, phpc CLI, Docker, docs, JIT compliance |
Largely β |
| 1 β Language | OOP, types, includes, ::class |
VM/JIT strong; native AOT gaps remain |
| 2 β Stdlib | Web builtins, filesystem, JSON, regex | Ongoing batches; audit in repo |
| 3 β Web AOT | phpc build --project, deploy, runtime includes |
Link β ; execute partial (North Star 1) |
| 4 β Polish | MiniWebApp gates, HTTP smokes, doc sync | Active |
Current active phase: Phase 4 polish (AOT execute matrix + HTTP smokes) while self-host waves continue in parallel.
| Example | VM | AOT link | AOT execute |
|---|---|---|---|
| 000β002, 004 | β | β | β |
| 003-MiniWebApp | β | β | π§ partial (home β ; #676) |
Commands: ./phpc run, ./phpc build, ./phpc serve, make examples-aot-smoke (see README).
Compiler lowers statements/expressions to OpCodes. Unsupported constructs throw LogicException (βnot yet loweredβ).Internal builtins (ext/standard/, ext/types/).clang via lib/AOT/Linker.php (not in self-host bundle yet).| Issue | Area | Impact |
|---|---|---|
| #676 | North Star 1 execute | Unskip MiniWebApp PHPUnit + shell smokes |
| #878β#849 | AOT bisect | Layout/includes/superglobals in native 003 |
| #828 | Self-host JIT | Object_.php external property children |
| #84 | Self-host tree | Full lib/ bundle growth + namespaces |
| #57 | Self-host runtime | Try/catch unwind in native bundle |
| M3βM5 | North Star 2 | Native PHP β rebuild compiler β full tree (#1056) |
./script/bootstrap-wave-check.sh before opening a PR.docs/pages/development-status.md) when a user-visible milestone lands.