Back to Blog
What TypePHP Actually Is (and Isn’t)
TypePHP is Swoole’s AOT compiler for PHP, not OPcache, not JIT, and not “PHP becomes Go overnight.” Here’s the honest map using their own comparison table.
Back
Engineering
Table of contents
What TypePHP Actually Is (and Isn’t)
If you write PHP for a living, you’ve seen the pattern: a new tool ships, the timeline fills with “this changes everything,” and someone quietly asks whether they should rewrite their Laravel app next weekend.
TypePHP is the latest candidate for that cycle. The tagline is blunt (compile PHP to native binaries), and the repo is real: swoole/typephp, from the same ecosystem as Swoole. As of this writing the project is on v0.9.x, targets PHP 8.4–8.5, and is licensed GPL-3.0.
So let’s kill the myth early.
TypePHP does not mean “drop your FPM workers and ship Go overnight.” It means something more specific, and more interesting, once you separate AOT, OPcache, and JIT.
Claims below are checked against the TypePHP README and incompatible-features doc as of 18 Sep 2026. Where marketing and docs differ, I follow the docs.
Quick answer
| If you mean… | TypePHP is… |
|---|---|
| A faster PHP for every existing app | No. Not drop-in; defined subset + stricter rules |
| An AOT compiler that lowers PHP → C++ → native code | Yes |
| A replacement for OPcache | No. Different job |
| The same thing as PHP 8’s JIT | No. Different timing and model |
| Worth watching if you ship CLI tools, CPU-heavy workers, or native extensions | Maybe yes, with eyes open |
What TypePHP claims to be
From the project README, TypePHP is an Ahead-Of-Time (AOT) compiler:
- Parse PHP (plus optional stubs / C++ sources)
- Lower function bodies to C++17
- Compile that to native machine code
Outputs include a native executable (bin), a loadable PHP extension (ext), a shared library (lib), and WASM/WASI targets depending on toolchain.
Two details that matter for credibility:
- The compiler itself is written in PHP and is self-hosting.
tpcis built by compiling TypePHP’s own PHP sources with TypePHP. - Dynamic PHP values, many internals, and Zend interop still go through PHPX / the embed runtime. Binary mode does not require you to run
php yourscript.php, but the shipped artifact still links the PHP/PHPX stack the docs describe. Native entry is not “zero PHP runtime forever.”
That last sentence is the sober version of the hype.
AOT vs OPcache vs JIT (their table, explained)
TypePHP’s own README compares three worlds. I’m reproducing the structure; the wording is theirs.
| TypePHP AOT | Opcode cache (OPcache) | JIT (PHP 8+) | |
|---|---|---|---|
| Compilation target | Native machine code | Bytecode | Machine code (trace) |
| Startup / warm-up | None (already compiled) | Per-process warm-up | JIT warm-up |
| Type-driven optimization | Compile-time, full-program | None | Limited, trace-based |
| Native executable output | Yes | No | No |
| Source code protection | Compiled to machine code | Bytecode (reversible) | Bytecode (reversible) |
| Deterministic performance | Yes | No | No |
OPcache (what most of us already run)
OPcache caches opcodes, the bytecode Zend executes. It removes repeated parse/compile of .php files inside a process. It does not turn your app into a standalone native binary. Warm-up still exists per process. This is table stakes for production PHP, not a rival to TypePHP.
JIT (PHP 8+)
The JIT compiles hot traces to machine code while the process runs. Gains show up after warm-up, mostly on CPU-bound paths, and behavior is less “one binary, always the same” than a full AOT build. Useful. Not the same product category as “ship ./mytool.”
TypePHP AOT
Compilation happens before you ship. The artifact is native code chosen at build time, with type-driven lowering across the program the compiler can see. That’s why their table stresses no warm-up, native executable output, and deterministic performance.
If you remember only one sentence: OPcache and JIT optimize how Zend runs PHP; TypePHP tries to stop running your hot paths as Zend opcodes at all (for the code it successfully compiles).
The myth: “PHP becomes Go overnight”
Three reasons that story fails.
1. Compatibility is intentional and limited
The README is unusually honest for a launch-era project: TypePHP supports a defined, testable subset of PHP. There is a dedicated incompatible-features list. Examples that bite real apps immediately:
- No executable statements at global scope. Binary mode wants a global
main()returningvoid - No variable-variables (
$$var) - Nested named class / function declarations inside functions are out
- Once a local is inferred as a concrete native type, reassigning an incompatible type in that scope is rejected
- Always-strict typing:
strict_types=0is rejected;strict_types=1is redundant
That is not “paste your Laravel public/index.php and click compile.”
2. Native scalars change how you write PHP
Since 0.8, inferred int / float / bool locals use native storage by default. The old use native_types switch is gone. Escape hatches exist (std::any(), use varint_types) when you need Zend-style integer widening or dynamic identity. That’s a feature for performance, and a tax if your code leans on PHP’s forgiving number semantics.
3. “Native binary” still has a runtime story
README clarity again: binary mode starts from a native executable and does not require a separate PHP CLI invocation, but the package still embeds/links PHPX, libphp, and configured native libraries. You’re shipping a compiled program, not a magical language escape hatch that erases PHP’s ecosystem dependencies.
So no: TypePHP is not Go with dollar signs. It’s closer to “PHP-shaped source with a serious AOT backend and stricter contracts.”
What it is good for (my take)
I’d watch TypePHP for:
- CLI tools you want to ship as a binary
- CPU-heavy workers (numeric / container-heavy paths) where you’re willing to write to the compiler’s rules
- PHP extensions / shared libs via
ext/libmodes when you already live near C++ - Teams that already touch Swoole / PHPX and can absorb pre-1.0 breakage (their changelog warns public APIs may change before 1.0)
I would not start by pointing it at a large Laravel monolith and expecting a green build. Framework PHP is dynamic by culture: containers, facades, magic, runtime class loading. TypePHP’s value shows up where you want constraints.
How this fits next to tools you already know
| Tool | Job |
|---|---|
| OPcache | Make normal PHP requests cheaper |
| JIT | Speed hot traces inside Zend |
| RoadRunner / Octane / Swoole HTTP | Change process model / concurrency |
| TypePHP | Compile selected PHP to native artifacts under stricter typing |
Different layers. Confusing them is how Twitter threads get written.
Closing
TypePHP is one of the more ambitious PHP experiments in years: AOT to native code, self-hosted compiler in PHP, explicit subset, and a comparison table that actually helps instead of hiding the tradeoffs.
The useful mental model is not “PHP is obsolete.” It’s:
Some PHP programs can be compiled ahead of time into native artifacts, if you accept the type rules and the compatibility boundary.
That’s less viral than “PHP becomes Go.” It’s also true enough to be useful.
Next in this series (if I keep going): a hands-on hello.php → tpc on a real machine, then an honest pass at the incompatible-features list against a tiny Laravel-shaped sample. Not to dunk on the project, but to draw the adoption line clearly.
Sources (checked 2026-09-18)
- swoole/typephp README: AOT definition, self-hosting, Why TypePHP comparison table, strengths, binary runtime packaging notes, PHP 8.4–8.5 / GPL-3.0 badges
- INCOMPATIBLEPHPFEATURES.md: global scope /
main(), typing restrictions,strict_typespolicy - CHANGELOG.md: 0.8 native-scalar default, removal of
use native_types,std::*API cleanup, pre-1.0 compatibility policy - TypePHP releases: v0.9.0 published 2026-09-17
- Homepage: swoole.com/aot
Comments
No comments yet
Loading comments...