VM
phpc run · bin/vm.php
Reference interpreter — broadest coverage, slowest. Default for dev and compliance.
php-compiler is a CFG-based compiler with a bytecode VM,
LLVM 9 JIT, and AOT linking. Ship CLI tools and small web apps
that run without Zend PHP at runtime after phpc build or phpc deploy.
The north star is the compiler rebuilding its own lib/ tree — today you can
reproduce M0 link (compiler_minimal bundle OK), the M4 bootstrap loop
(make bootstrap-loop-probe), and M5 presenter (make north-star5-verify-fast)
on a clean clone with Docker and LLVM 9.
git clone https://github.com/PurHur/php-compiler.git
cd php-compiler
composer install
./phpc test --fast
./phpc build -o /tmp/hello examples/000-HelloWorld/example.php
./phpc serve examples/003-MiniWebApp
This project continues a research compiler originally written in PHP. Credit the idea to the original author; this fork is a separate continuation under MIT.
| Original project | ircmaxell/php-compiler |
| Original author | Anthony Ferrara (ircmaxell) — MIT © 2019 |
| This fork | PurHur/php-compiler — LLVM JIT/AOT, phpc CLI, web examples, self-host ladder |
The concept of a PHP-in-PHP compiler with VM, JIT, and native compilation comes from Anthony Ferrara’s work. It is not an official release from the original author unless stated otherwise.
Most PHP runs on Zend (opcode VM in C). php-compiler parses with php-cfg, lowers to internal opcodes, then executes via one of three backends.
phpc run · bin/vm.php
Reference interpreter — broadest coverage, slowest. Default for dev and compliance.
bin/jit.php
LLVM MCJIT — compile at startup, run native code. Some CFGs fall back to VM.
phpc build · bin/compile.php
Standalone executable — no PHP installed on the server at runtime.
Targets a deliberate PHP 8 subset for CLI and CGI-style web apps (superglobals, routing, templates, sessions, uploads, JSON).
Examples under examples/ are integration test fixtures, not a separate product.
Active research: self-host — the compiler compiling its own lib/ without Zend in the bootstrap loop.
Needs PHP 8.1+, Composer. LLVM 9 only for build, JIT, and full CI (not for phpc test --fast).
Full walkthrough:
GETTING-STARTED.md.
git clone https://github.com/PurHur/php-compiler.git
cd php-compiler
composer install
./phpc test --fast
./phpc build -o /tmp/hello \
examples/000-HelloWorld/example.php
/tmp/hello
Standalone executable — no php at runtime.
./phpc serve examples/003-MiniWebApp
Open http://127.0.0.1:8080/ — router, templates, JSON API.
make docker-build-22 # once
./script/docker-exec.sh -- bash -lc \
'composer install --ignore-platform-reqs -q \
&& script/apply-patches.sh \
&& make bootstrap-selfhost-link'
./build/selfhost
Expect compiler_minimal bundle OK — native link of a minimal lib/ bundle (experimental). Needs LLVM 9.
make bootstrap-loop-probe
make north-star5-verify-fast
# pre-merge bootstrap only (~1h):
./script/north-star5-verify.sh --strict
Full bootstrap ladder (gen-1→gen-2→gen-3 + full-revision) and M5 presenter — heavy; see GETTING-STARTED §7.
Subset compiler — not full Zend PHP. Use phpc lint before shipping your own code.
phpc CLI
Unified developer interface (./phpc → bin/phpc.php).
Legacy bin/vm.php, bin/jit.php, and bin/compile.php still work.
| Command | Purpose |
|---|---|
phpc run | Run on the VM; -q / -p for CGI-style superglobals |
phpc serve | Dev HTTP server (VM); phpc serve --aot for a prebuilt binary |
phpc build | AOT compile; --project uses phpc.json |
phpc deploy | Package binary + public/ into a deploy tree |
phpc lint | Report unsupported syntax in a file or tree |
phpc test | CI locally; --fast = VM/compliance only (no LLVM) |
phpc init | Scaffold phpc.json (miniwebapp, sessionsweb, fileupload profiles) |
phpc doctor | Environment and example gate probes |
Reference apps in examples/ prove VM, AOT link, native execute, and deploy paths.
examples/README.md
| Example | Highlights |
|---|---|
| 000–002 | CLI hello, simple web, CGI query params |
| 003-MiniWebApp | Router, templates, contact form, JSON API — AOT execute green |
| 004-ApiJson | JSON API |
| 005-SessionsWeb | session_start, flash messages |
| 006-FileUploadWeb | Multipart $_FILES |
| 007-ThrowsWeb | Caught exceptions in forms |
| 008-SelfHostProbe | Self-host presenter probe |
| 009-FastCGIWeb | FastCGI-oriented layout |
make web-smoke # lint + VM smoke make examples-aot-smoke # AOT link + execute (LLVM required) make examples-web-smoke # phpc serve + HTTP curls
Not a drop-in Zend replacement. Capabilities differ by backend — VM is broadest; AOT is strictest. Full PHP vs us comparison · Gap tables.
| Column | Meaning |
|---|---|
| VM | phpc run — broadest language coverage |
| JIT | bin/jit.php — native MCJIT; some CFGs use VM fallback |
| AOT | phpc build — standalone binary; many constructs blocked at link |
match, namespaces, parent::classfn () => — VM + JIT IR (use() value and ref)try / catch / finally — VM compliance; JIT IR verifiedphpc deployarray_map callbacks on VM| Area | VM | JIT / AOT |
|---|---|---|
| Try / catch / finally | Yes | IR only; execute → VM |
| Closures / arrow functions | Yes | JIT IR |
Generators (yield) |
Yes | VM fallback |
| Enums in AOT | VM | No |
| M3 inventory emit (HelloWorld) | Native | Native |
M4 bootstrap loop (bootstrap-loop-probe) |
— | Native |
M5 presenter (north-star5-verify-fast) |
— | Strict ✅ |
fix/spine-aot-jit-blockers @ a8cffaa0e (15 Jun 2026, LLVM 9).
M2 spine SSOT: php script/bootstrap-spine-count.php → **4287** / **4287** Phase A inventory (literal coverage ✅).
M4: make bootstrap-loop-probe full ladder ✅.
M5: make north-star5-verify-fast ✅ daily; --strict pre-merge; VM driver probe ~20ms in CI loops.
Remaining: MCJIT execute ([#98](https://github.com/PurHur/php-compiler/issues/98)); honest PHP main() in full spine AOT (native bundle-OK probe is bootstrap smoke).
Compiled-only cold boot on empty build/: BOOTSTRAP_M5_NO_ZEND=1 make bootstrap-selfhost-link ✅ ([#3053](https://github.com/PurHur/php-compiler/issues/3053)).
Experimental path: compiler compiling its own lib/ tree.
Tracker #1492.
Short status page.
Minimal + compiler-shaped bundles; compile-smoke AOT echo.
Spine **4287** / **4287** Phase A inventory — literal coverage ✅; native link + lint ✅ (#8559).
HelloWorld + inventory argv driver strict emit_path=native ✅;
production bin/compile.php inventory path on gen-2 driver ✅
(#3024 closed).
make bootstrap-loop-probe full ladder ✅ — gen-1→gen-2 native, gen-2→gen-3 full-spine recompile,
full-revision argv probe (#1498,
#2880).
Vendor prelink 3/3 ✅; committed .o cold boot ✅;
north-star5-verify-fast ✅ daily; --strict pre-merge; spine **4287** / **4287**; prelinked gen-0 refreshed;
fast VM execute probe (~20ms); compiled-only cold boot via BOOTSTRAP_M5_NO_ZEND=1 ✅
(#3053,
#8559,
#1492).
PHP 8.1+ (8.2 recommended), Composer, LLVM 9 for JIT/AOT (bundled via script/install-llvm9.sh).
composer install
script/apply-patches.sh
./script/install-llvm9.sh # optional until build/CI
Image php-compiler:22.04-dev — full CI without host PHP/LLVM.
make docker-build-22
make test
Harness hosts: make test-harness or ./script/docker-ci-local.sh.
We do not accept drive-by GitHub issues or pull requests without prior coordination. Contact maintainers on other channels first; align with the AI-agent workflow before investing time here. Forks are welcome under MIT.