# TypePHP vs PHP Bytecode Caches and JIT Compilers: How AOT Changes PHP Execution

> Discover TypePHP AOT compilation versus PHP bytecode caches and JIT compilers. TypePHP generates native binaries for faster execution without the Zend interpreter.

- Repository: [Swoole Project/typephp](https://github.com/swoole/typephp)
- Tags: deep-dive
- Published: 2026-08-30

---

**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`](https://github.com/swoole/typephp/blob/main/src/compiler.php) and implemented in [`src/Translator.php`](https://github.com/swoole/typephp/blob/main/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:

```php
// hello.php
<?php
function main(): void {
    echo "Hello from TypePHP\n";
}

```

```bash

# 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:

```ini
opcache.enable=1
opcache.memory_consumption=128

```

```php
<?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:

```ini
opcache.jit=1205   ; enable tracing JIT
opcache.jit_buffer_size=100M

```

```php
<?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.php`](https://github.com/swoole/typephp/blob/main/src/Translator.php) performs 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`](https://github.com/swoole/typephp/blob/main/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 in [`docs/en/COMPILATION_MODES.md`](https://github.com/swoole/typephp/blob/main/docs/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`](https://github.com/swoole/typephp/blob/main/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`](https://github.com/swoole/typephp/blob/main/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`](https://github.com/swoole/typephp/blob/main/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`](https://github.com/swoole/typephp/blob/main/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.