TypePHP is an ahead-of-time compiler from Swoole that translates PHP source into C++17 and then into native machine code. There's no interpreter and no opcode cache involved at runtime, so what you get back is a binary that runs directly on the CPU. The compiler itself is written entirely in PHP and is self-hosting, which means the tpc binary is built by compiling the compiler's own PHP source.
Here's what it gives you:
- Three build modes:
binproduces a native executable,exta loadable PHP extension, andliba shared library alongside a generated.stub.php use native_typesmapsint,float, andboolonto C++int64_t,double, andboolinstead of zvals- Typed containers,
std::vector,std::map,std::ordered_map, andstd::array, with element types fixed at compile time - High-precision numerics, with
bigIntbacked by GMP,bigFloatby MPFR, anddecimalby libmpdec - Methods on primitives like
$s->upper()and$arr->contains(3)resolve at compile time into direct C function calls, with no runtime dispatch - Mixed C++ and PHP, so you can write a hot kernel in C++, declare its signature in a
.stub.php, and call it like an ordinary PHP function - Compile-time code generation from the
#[Getter],#[Setter],#[With],#[Constructor],#[Printer], and#[Arrayable]attributes, which generate typed methods from property declarations - Cross-platform output for Linux, macOS, and Windows on x64 and ARM64, plus WASI 0.2 and browser builds through jco
TypePHP is framework-agnostic. It compiles PHP source, so nothing about it is tied to Laravel, Symfony, or any other framework, though the compatibility limits below rule out most existing application code.
Three ways to build
The mode is set with -m, and bin is the default:
# Native executable bin/tpc.php app.php -o myapp # PHP extension bin/tpc.php extension/ -m ext -o my_extension # Shared library, also generates mylib.stub.php bin/tpc.php lib/ -m lib -o mylib
Binary mode needs a global main() function, declared either with no parameters or as main(int $argc, array $argv), and it must return void. Extension and library modes don't need one.
For anything past a single file, build settings go in a project.yml with sources, link-libs for native linker dependencies, and ext-deps for required Zend extensions. Conditional source entries can key off PHP_VERSION_ID or PHP_OS_FAMILY, so a project can include an 8.5-only directory or a Windows-only one.
Native types are where the speed comes from
Adding use native_types at the top of a file opts scalar declarations into fixed native storage:
<?php use native_types; function fib(int $n): int { if ($n == 1 || $n == 2) { return 1; } return fib($n - 1) + fib($n - 2); }
With that declaration, $n is a C++ int64_t rather than a zval, and the arithmetic compiles to plain CPU instructions instead of ZendVM calls. The trade is that a value typed this way cannot later hold an incompatible type, which is the whole point but also the thing that breaks dynamic code.
Containers work the same way. std::vector(Type::Int) gives you a growable list whose elements are known to be integers at compile time, so indexing doesn't go through a hash table.
Generating methods from properties
The code generation attributes are consumed while the class is lowered, and the generated methods keep the declared property types:
<?php #[Printer(fields: ['id', 'name'])] #[Arrayable(fields: ['id', 'name'])] final class User { #[Constructor, Getter, With] public int $id; #[Constructor, Getter, Setter] public string $name = 'guest'; }
That gives User a generated constructor, getId(), withId(), getName(), setName(), __toString(), and toArray(), all typed. #[With] clones the object, updates the clone, and returns it. The generated methods take part in the same inheritance and final-method checks as hand-written ones, so a name collision is a compile error rather than a surprise at runtime.
The benchmark numbers
TypePHP runs the bench.php and micro_bench.php language benchmarks that ship with the PHP source tree, compiled at -O3:
| Benchmark | Interpreted PHP | TypePHP AOT | Speedup |
|---|---|---|---|
bench.php (total) |
5.034 s | 0.603 s | ~8x |
micro_bench.php (total) |
13.045 s | 2.021 s | ~6.5x |
There's a separate container benchmark running a 10000x100000 element update loop:
| Implementation | Time |
|---|---|
| PHP array (JIT) | 67.6 s |
std::array (TypePHP AOT) |
6.4 s |
C++ std::vector |
6.2 s |
The project calls these a measurement snapshot rather than a guarantee, and notes that PHP version, compiler, CPU, and enabled extensions all move the numbers. Even with that caveat, the container result lands within a few percent of hand-written C++.
What it won't compile
TypePHP supports a defined, tested subset of PHP and does not claim drop-in compatibility. The documented restrictions include:
- Global scope is declaration-only. Executable statements have to live inside a function or method
- Binary mode enforces the strict
main()signature .stub.phpfiles must have empty bodies, and#[Native]classes aren't allowed in them- A number of dynamic reference, declaration, closure, and reflection patterns are unsupported on purpose
What it does handle is current syntax. PHP 8.4 property hooks and asymmetric visibility both compile, as do PHP 8.5's clone()-with and (void) discard expressions. Dynamic values, internal functions, reflection, and object metadata still interoperate with the Zend runtime through PHPX, so it isn't all-or-nothing. But the compatibility boundary is treated as part of the public contract, with both positive and negative tests behind it, and the project keeps a specific list in docs/INCOMPATIBLE_PHP_FEATURES.md. Check that list against your code rather than assuming anything absent from the README works.
Installing it
TypePHP needs PHP 8.4 or 8.5 with development headers and php-config, GCC 9+ or Clang with C++17, CMake 3.24+, Composer 2, and the GMP and MPFR libraries. Binary and shared-library builds also need PHP's embed SAPI (libphp.so or libphp.dylib), and tpc.php can offer to download the PHP source and build that for you on Linux.
composer require --dev swoole/typephp
vendor/bin/tpc.php project.yml
Linux x64 is the primary development and full-test CI target. Windows, macOS, ARM64, and WASI backends exist, but which one you can actually build depends on whether PHP embed and the toolchain are available on that host.
TypePHP is licensed under GPL-3.0. The current release is v0.6.6, and the project is under active development. Visit the GitHub repo for the documentation and the incompatible-feature list.