TypePHP vs PHP Bytecode Caches and JIT Compilers: How AOT Changes PHP Execution
TypePHP is an Ahead-Of-Time (AOT) compiler that translates PHP source code into C++ and then into native machine code, producing standalone binaries that run directly on the CPU without the Zend interpreter, unlike OPcache or JIT compilers which rely on runtime bytecode execution.
The swoole/typephp project redefines PHP execution by eliminating the traditional interpreter loop entirely. While standard PHP relies on the Zend engine to process bytecode at runtime, TypePHP implements a complete Ahead-of-Time (AOT) compilation pipeline that generates native executables. This architectural shift offers deterministic performance and source protection that differ fundamentally from PHP bytecode caches or modern JIT compilers.
Core Architecture Comparison
The following table from the project README highlights the operational differences between TypePHP and traditional PHP execution models:
| Feature | TypePHP AOT | PHP Opcode Cache (OPcache) | PHP JIT (PHP 8+) |
|---|---|---|---|
| Compilation target | Native machine code | Bytecode stored in shared memory | Machine code (trace-based) |
| Startup / warm-up | None – binary is already compiled | Per-process warm-up (first request loads cache) | JIT warm-up (traces must be collected) |
| Type-driven optimisation | Full-program compile-time analysis, static typing, universal methods, native containers | None – runtime opcodes are unchanged | Limited – only hot traces are optimised |
| Output | Executable / .so / shared library |
In-memory bytecode cache (no file) | In-memory machine code |
| Source protection | Compiled to native code (hard to reverse) | Bytecode can be dumped and de-obfuscated | Bytecode can be dumped and de-obfuscated |
| Deterministic performance | Yes – same binary every run | No – cache population can vary | No – JIT decisions may differ per-run |
According to the swoole/typephp source code, TypePHP generates a stand-alone binary (or extension/shared library) that runs directly on the CPU, while OPcache and JIT both require the Zend runtime to execute or generate code.
The TypePHP Compilation Pipeline
TypePHP operates through a sophisticated build process orchestrated by src/compiler.php and implemented in src/Translator.php. This pipeline transforms PHP source into optimized C++17 before native compilation.
Two-Phase Compilation Process
The compiler executes a prepare phase that builds a complete symbol model without allocating runtime IDs. Subsequently, the convert phase lowers the AST to C++17, enabling whole-program optimization techniques such as constant folding and dead-code elimination across file boundaries. This contrasts with OPcache, which caches files individually without cross-file analysis.
Native Type System Mapping
TypePHP maps PHP primitives (int, float, bool) and high-precision types (bigInt, decimal, bigFloat) directly to C++ scalar types. As documented in the README, this enables arithmetic operations to emit as plain CPU instructions rather than Zend VM calls, eliminating the overhead of opcode dispatch.
Universal Methods Resolution
The compiler resolves method calls on primitives—such as $s->length() or $arr->contains(3)—at compile time to direct C/C++ functions. This eliminates v-table lookups and reflection overhead that typically occur in the Zend engine during runtime execution.
How TypePHP Differs from OPcache
While OPcache stores Zend opcodes in shared memory to avoid repeated parsing, it still requires the PHP interpreter to fetch and execute each opcode sequentially. TypePHP eliminates the interpreter entirely by producing native binaries. Additionally, OPcache operates incrementally, caching already-compiled files without performing whole-program optimization. TypePHP recompiles the entire project, enabling aggressive cross-file inlining and dead-code removal that OPcache cannot achieve.
How TypePHP Differs from PHP JIT
The PHP JIT compiler introduced in PHP 8+ compiles hot traces at runtime, incurring a warm-up period and producing machine code specific to observed execution paths. TypePHP generates a single binary containing all code with no warm-up requirement. Furthermore, JIT optimization applies only to traced execution paths, whereas TypePHP can optimize any reachable code because it possesses the complete AST at compile time.
Practical Implementation Examples
The following examples demonstrate the three distinct approaches to PHP execution.
Compiling with TypePHP AOT
TypePHP produces a native binary through its CLI entry point:
// hello.php
<?php
function main(): void {
echo "Hello from TypePHP\n";
}
# Compile & run
bin/tpc.php hello.php -O3 -r # -r runs the binary immediately
# Output:
# Hello from TypePHP
The tpc binary is itself self-hosting—the compiler is written in PHP and compiled by TypePHP, demonstrating the maturity of the AOT pipeline.
Using OPcache (Runtime)
Standard OPcache requires the PHP interpreter with shared memory configuration:
opcache.enable=1
opcache.memory_consumption=128
<?php
// hello.php
echo "Hello from OPcache\n";
Run with the regular PHP interpreter; the first request populates the opcode cache, subsequent requests are faster but still interpreted from shared memory.
Using PHP JIT (Runtime)
JIT compilation occurs within the Zend engine at runtime:
opcache.jit=1205 ; enable tracing JIT
opcache.jit_buffer_size=100M
<?php
function fib(int $n): int {
return $n < 2 ? $n : fib($n-1) + fib($n-2);
}
echo fib(30);
The script runs under the normal PHP binary; hot loops are compiled to machine code after a few iterations, incurring warm-up overhead.
Summary
- TypePHP is an AOT compiler that produces standalone native binaries, while OPcache and JIT rely on runtime interpretation of Zend bytecode.
- The compilation pipeline defined in
src/Translator.phpperforms whole-program analysis across prepare and convert phases, enabling optimizations impossible in file-by-file caching systems. - Universal methods and native type mapping eliminate Zend VM overhead by resolving calls at compile time rather than runtime.
- Unlike JIT, TypePHP requires no warm-up period and offers deterministic performance across executions, as documented in
benchmark/bench.php. - Source code protection is inherent to the AOT model, as TypePHP compiles to native machine code rather than storable bytecode that can be dumped and de-obfuscated.
- The compiler supports three build modes (
bin,ext,lib) as detailed indocs/en/COMPILATION_MODES.md, providing flexibility for different deployment scenarios.
Frequently Asked Questions
How does TypePHP handle dynamic PHP features?
TypePHP links against the PHPX embed library (libphp.so) only for features that cannot be statically resolved, such as dynamic function calls. However, the majority of user code runs as native C++ without any Zend opcode dispatch. Static analysis during the prepare phase in src/compiler.php resolves type information for universal methods and primitive operations at compile time.
Can TypePHP run existing PHP frameworks?
TypePHP supports standard PHP syntax but requires static typing discipline for optimal performance. According to docs/en/UNIVERSAL_METHODS.md, features relying heavily on runtime evaluation may need adjustment, as the compiler performs aggressive dead-code elimination and cross-file optimization that assumes compile-time type information.
Why choose TypePHP over PHP 8+ JIT for performance-critical applications?
TypePHP offers deterministic performance—the same binary executes identically every run—whereas JIT compilation decisions may vary based on runtime conditions and trace collection. The benchmark/bench.php file in the repository demonstrates scenarios where AOT compilation eliminates the warm-up penalty and trace de-optimization risks inherent in runtime JIT systems.
What output formats does TypePHP support?
As documented in docs/en/COMPILATION_MODES.md, TypePHP supports three distinct build outputs: bin (standalone executable), ext (shared PHP extension), and lib (static library). This flexibility allows integration with existing PHP installations or deployment as completely independent binaries, unlike OPcache or JIT which remain tightly coupled to the Zend engine.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →