Introduction to Swoole's AOT Compiler A paradigm shift for PHP — from interpreted scripts to native binaries. PRESENTED BY Albert Chen target native binary runtime libphp.so + libphpx.so speedup up to 150×
interpreters only — no JIT in the lineup. 1B NESTED-LOOP ITERATIONS · SECONDS (LOWER IS BETTER) 0 … 32s PHP php 8 · interpreter 10.76s Ruby cruby · interpreter 27.92s Python cpython 3.13 31.59s ~3× Stock PHP outruns CPython by ~3× and CRuby by ~2.6× on this workload — the interpreter itself is well-tuned. // 1B nested loops · benjdd.com/languages2 03 / 24 · PHP IS NOT SLOW stock interpreters
the gap is huge. This is why nobody uses PHP for CPU-bound workloads. SAME WORKLOAD · SECONDS 0 … 12s Rust --release 0.515s C gcc -O2 0.519s Go go build 1.05s PHP JIT opcache.jit=on 2.41s PHP interpreter 10.76s ~20× Even with JIT enabled, PHP is still ~5× slower than C/Rust. The interpreter is roughly 20× off. // 1B nested loops · benjdd.com/languages2 05 / 24 · THE REAL GAP interpreted vs compiled
looks like PHP. A Zend API wrapper, redesigned in 2025. Same dynamic feel, full GC, zero manual memory. // WHAT IT IS A header-only C++ library mirroring PHP's standard library. Built by the Swoole team in 2016 — fully redesigned for 2.0 in 2025. var keyword — assign any type, just like PHP. Operator overloading that follows PHP semantics. Automatic GC + refcounting — no leaks, no overruns. sizeof(Variant) == sizeof(zval) — 16 bytes, ABI-identical. var a = "hello world"; var b = 2025; var c = a; // shallow copy b += 100; a.append(b); // "hello world2125" // bit ops, comparisons — all PHP rules var d = b << 3; if (a == c) { ... } // list & associative arrays var e = {"php", "swoole", "is", "best"}; var f = { {"key", "value"}, {"key2", 2024.08} }; // dynamic typing in c++ 12 / 24 · PHPX php-flavoured c++ · gc · 16-byte variant
no boilerplate. Functions, objects, constants — the entire stdlib is one include away. Call any PHP function directly — the entire stdlib. Built-in classes auto-generated by reflection. Predefined constants usable as-is. References via C++ & / * — familiar pointer semantics. // INSTALL composer create-project \ swoole/phpx-ext myext // call any PHP function var rs = file_get_contents("/tmp/file.txt"); var_dump(rs); // hashing var data = random_bytes(1024); var h1 = sha1(data); var h2 = hash("sha1", data); // objects — built-in classes Redis redis{}; redis.connect("127.0.0.1", 6379); redis.set("phpx_key", "hello phpx"); // predefined constants var v = PHP_VERSION; var o = PHP_OS; // example.cpp · PHPX 2.0 13 / 24 · PHPX IN PRACTICE stdlib · objects · refs
AOT doesn't. PROJECT MECHANISM ECOSYSTEM REALITY HHVM JIT → eventually a separate language (Hack) ✕ Diverged from PHP. Not Zend-compatible anymore. KPHP Transpiles a subset of PHP to C++ ✕ A separate PHP implementation. No PHP extensions. Swoole AOT Reuses ZendPHP runtime + PHPX ABI bridge ✓ Composer, all built-ins, all native extensions just work. // THE TRICK Swoole AOT doesn't reinvent the wheel. It throws out the opcode handler — not the runtime — and links straight against libphp.so . That's why every PHP extension keeps working. 15 / 24 · HHVM · KPHP · SWOOLE 100% extension compatibility
the entry point. Top-level scripts have no place in a compiled binary; everything lives inside a function. The AOT compiler refuses unbounded top-level code. For bin mode, you supply a main() as the system entry. The signature mirrors C: int $argc, array $argv . // GOOD NEWS The PHP standard library is fully available inside main() . echo , var_dump , the lot. <?php // AOT entry point — must exist in bin mode function main(int $argc, array $argv): void { echo "Hello World!\n"; var_dump(PHP_VERSION); } app.php 16 / 24 · ENTRY POINT function main(): void
are resolved at compile time. Variables become C++ memory addresses — $$name has nothing to bind to. extract() mints local symbols at runtime and can't be analysed. Migrate to explicit array keys or object properties. // TRADE-OFF You lose runtime symbol magic. You gain a compiler that can prove what your code touches. // ❌ AOT can't resolve runtime-named locals $name = "foo"; $$name = "bar"; extract(['a' => 1]); // ✅ Use an explicit map instead $data = []; $name = "foo"; $data[$name] = "bar"; // rule of thumb 17 / 24 · STATIC SYMBOLS no $$ · no extract()
— trade VM tricks for native primitives. yield generators rely on a ZendVM state machine — gone. Use Swoole/Fiber real coroutines (Channels) for streaming. break 2 / continue 3 have no C++ counterpart. Reach for goto labels — or throw to escape. // ❌ generator — depends on the VM function getNumbers() { for ($i = 0; $i < 5; $i++) yield $i; } // ✅ Swoole coroutine + channel use Swoole\Coroutine\Channel; $chan = new Channel(5); Swoole\Coroutine::run(function () use ($chan) { for ($i = 0; $i < 5; $i++) $chan->push($i); }); // ❌ break 2 has no C++ equivalent // ✅ goto a label that the linker can resolve foreach ($arr1 as $a) foreach ($arr2 as $b) if ($a === $b) goto END_LOOP; // preferred patterns 18 / 24 · CONSTRAINTS yield → coroutines · break N → goto
a .so. Same Nginx + PHP-FPM stack — with a hot path that runs at C++ speed. Nginx → PHP-FPM → myapp.so Web request · standard pool · AOT-compiled hot path // 01 · BUILD -m ext emits a standard PHP dynamic library. // 02 · LOAD Drop one line in php.ini — like Redis or PDO. // 03 · USE Hot functions execute as native machine code, no VM dispatch. # 1. Build the extension $ ./bin/compiler.php examples/extension -O2 -m ext -o myap # 2. Enable in php.ini extension=myapp.so # 3. Call from any controller <?php $start = microtime(true); $result = myapp_heavy_calculation(1_000_000); echo "done in " . (microtime(true) - $start) . "s"; build & load 23 / 24 · EXT MODE nginx + php-fpm + .so
& POSITIONING 2026.05 Preview First public preview — including direct calls into Python from PHP. 2026.10 Beta Most known issues resolved; ready for non-critical workloads. 2027.05 General Availability Production-ready — PHP as a static, compiled, system-grade language. Swoole-Compiler v4 isn't just an optimizer. It's the moment PHP becomes a statically-compiled language. 24 / 24 · ROADMAP preview · beta · GA