Compileer PHP naar een Native Binary Zonder Interpreter
Ongeveer vijftien jaar geleden probeerde Facebook de prestatieproblemen van hun monolith op te lossen met de HPHPc-compiler, die PHP naar C++ converteerde. Later verlieten ze deze aanpak ten gunste van de HHVM-virtuele machine, en PHP 8 introduceerde een ingebouwde JIT. Het leek erop dat het idee van een pure Ahead-Of-Time compiler voor PHP definitief in de geschiedenis was verdwenen. Het Swoole-team besloot het opnieuw te proberen en bracht het TypePHP-project uit.
Dit is een volwaardige AOT-compiler die volledig in PHP zelf is geschreven. Het vertaalt PHP 8.4+ broncode naar C++17 en compileert dit vervolgens via GCC of Clang naar native machinecode. Geen opcodes op runtime, geen JIT-opwarmtijd en geen interpreter in de runtime.
De compiler is volledig self-hosting. Het tpc hulpprogramma bouwt zichzelf vanuit PHP-bronnen, zonder enige C-gluecode in de compiler zelf.
Hoe TypePHP Werkt
Compilatie vindt plaats in twee fasen. Eerst parseert de analyzer de projectcode, verzamelt metadata over klassen en functies, en bouwt een complete symbol table. In de tweede fase worden functie-bodies vertaald naar C++17. In hot paths genereert de compiler snelle statische C++, terwijl voor dynamische constructies zoals reflection of systeemfunctie-aanroepen verbinding wordt gemaakt met de Zend runtime via de PHPX-laag.
De output kan een van drie formaten zijn:
- Uitvoerbaar binary (
bin). Een standalone bestand voor console-hulpprogramma's en daemons. Vereist een entry pointmain(). - PHP-extensie (
ext). Een reguliere.soof.dllmodule die kan worden geladen in standaardphp.ini. - Dynamische bibliotheek (
lib). Een binair bestand met gegenereerde.stub.phpbestanden voor aanroepen vanuit andere projecten. - WASI-component voor uitvoering in een WebAssembly-omgeving.
Wat Verandert er in de Syntaxis
TypePHP probeert niet alle dynamische trucs van standaard PHP te ondersteunen. De makers zetten in op strikte typing waar maximale snelheid nodig is.
Native Scalaire Typen
De use native_types directive vertelt de compiler om int, float en bool direct te mappen naar C++-typen (int64_t, double, bool). Een variabele met zo'n type kan niet langer plotseling van type veranderen halverwege de uitvoering van een functie. Maar de processor voert pure machine-instructies uit zonder uitpakken van zval.
<?php
use native_types;
function fib(int $n): int
{
if ($n == 1 || $n == 2) {
return 1;
}
return fib($n - 1) + fib($n - 2);
}
function main(int $argc, array $argv): void
{
$n = (int)$argv[1];
$begin = microtime(true);
echo fib($n) . "\n";
echo "Time: " . (microtime(true) - $begin) . "\n";
}
Het wordt gebouwd met een enkele opdracht:
bin/tpc.php fib.php -O3 -o fib
./fib 35
Strikt Getypte Containers
Reguliere PHP-arrays zijn veelzijdig maar geheugen-hongerig en langzaam vanwege hash-tabellen. TypePHP voegt std::vector, std::array, std::map en std::ordered_map structuren toe.
<?php
use native_types;
function main(): void
{
$vector = std::vector(Type::Int);
$vector[] = 10;
$vector[] = 20;
$vector[] = 30;
$sum = 0;
foreach ($vector as $val) {
$sum += $val;
}
echo "Sum: " . $sum . "\n";
$map = std::ordered_map(Type::String, Type::Int);
$map["alpha"] = 1;
$map["beta"] = 2;
}
In de tests van de ontwikkelaars duurde een loop die elementen in std::array bijwerkte 6,4 seconden versus 67,6 seconden voor een reguliere PHP-array met JIT ingeschakeld. De snelheid kwam essentially overeen met handgeschreven C++ vector (6,2 seconden).
Methoden op Primitieven
In plaats van een heleboel functies zoals strlen(), strtoupper() of in_array(), kun je methoden direct aanroepen op basistypen. De compiler lost dergelijke aanroepen op tijdens het bouwen en converteert ze naar directe C-functie-aanroepen zonder virtual table overhead:
<?php
function main(): void
{
$str = "hello world";
echo $str->upper() . "\n";
echo $str->substr(0, 5) . "\n";
$items = [1, 3, 5, 7];
var_dump($items->contains(3));
}
Template Code Generatie via Attributen
Om te voorkomen dat je tientallen getters en setters met de hand moet schrijven, verwerkt TypePHP aangepaste attributen tijdens compilatie:
<?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';
}
function main(): void
{
$user = new User(1);
$user->setName('Ivan');
$copy = $user->withId(2);
echo $user->getId() . "\n"; // 1
echo $copy->getId() . "\n"; // 2
echo $user . "\n"; // User(id=1, name=Ivan)
}
Het #[With] attribuut genereert een methode die het object kloont, het veld wijzigt en een nieuw exemplaar retourneert. Dit is handig voor immutable DTO's.
Directe C++ Integratie
Als er een algoritme ontbreekt in PHP, kun je het in C++ schrijven en in de buurt plaatsen. Linking vindt plaats via een stub-bestand met een lege body:
// math.cpp
#include <phpx.h>
using namespace php;
Int php_fast_sum(Int a, Int b) {
return a + b;
}
<?php
// math.stub.php
function fast_sum(int $a, int $b): int {}
<?php
// main.php
function main(): void
{
echo fast_sum(10, 20) . "\n";
}
Prestaties in Benchmarks
Volgens de metingen van de auteurs op standaard synthetische tests uit de php-src repository (bench.php en micro_bench.php met de -O3 vlag):
bench.phpvoltooit in 0,603 s versus 5,034 s voor de standaard interpreter (ongeveer 8x snelheidswinst);micro_bench.phpvoert uit in 2,021 s versus 13,045 s (6,5x snelheidswinst).
De cijfers zijn verwacht voor AOT-compilatie van wiskunde en vertakkingen. In echte webapplicaties gaat de meeste tijd naar I/O en database-bewerkingen, dus de verbetering zal daar bescheidener zijn. Maar voor computationele taken en background workers is het verschil merkbaar.
Beperkingen en Afwegingen
Je kunt een bestaand Laravel- of Symfony-project nog niet naar TypePHP porten. Er zijn een aantal strikte regels:
- Uitvoerbare code in global scope is verboden—alle code moet binnen functies of methoden leven.
- PHP 8.4 of 8.5 met de gecompileerde
libphp.sobibliotheek (embed SAPI) is vereist om een binary te bouwen. - Je hebt GCC 9+ met C++17-ondersteuning, CMake en GMP/MPFR-bibliotheken nodig voor nauwkeurige berekeningen.
- Sommige dynamische taalfuncties, zoals gratis type-switching of complexe referenties, worden expres niet ondersteund.
Het project.yml configuratiebestand helpt bij het beheren van afhankelijkheden en optimalisatie-vlaggen in grote projecten:
name: myapp
mode: bin
php-version: "8.5"
optimize: 2
job: 8
build-dir: build
cxx-std: c++17
sources:
- src
- cpp-src
link-libs:
- curl
Wie Heeft Voordeel bij Dit Project
TypePHP is actief in ontwikkeling. Het heeft minder dan duizend sterren op GitHub tot nu toe, maar het project wordt ondersteund door het ervaren Swoole-team.
Het is de moeite waard om het project te proberen als je het volgende nodig hebt:
- Bouw een lichtgewicht CLI-hulpprogramma of microservice als een single binary zonder dat je PHP op de doelserver hoeft te installeren.
- Verberg applicatie-broncode bij levering aan een klant on-premise, aangezien binaries aanzienlijk moeilijker te decompilen zijn dan bytecode.
- Schrijf een PHP-extensie met zware berekeningen zonder diep in C en Zend API te duiken.
- Versnel geïsoleerde computationele modules, zoals parsers, data packers of scoring-algoritmen.
Om te beginnen, clone je gewoon de repository, bouw een testscript via bin/tpc.php app.php en bekijk de gegenereerde C++ in de build-directory.
Gerelateerde projecten