How TypePHP Eliminates Interpretation: A Deep Dive into Its Compilation Process
TypePHP transforms PHP code into native binaries through a four‑stage offline pipeline—prepare, convert, compile, and build—leveraging C++ translation, system compilers, and linking, while preserving runtime flexibility via three execution modes and offering tools like the --dry flag to inspect generated C++ code.
01. Overview: Four‑Stage Pipeline
The official documentation defines the compilation process as four offline stages. prepare() scans, collects, and sorts all source files to produce a complete symbol table. convert() translates the PHP AST into equivalent C++ source code (visible with --dry). compile() hands the generated C++ to the system C++ toolchain (GCC, Clang, or MSVC) to produce object files where optimization flags such as -O2 or -O3 take effect. build() links the object files with the runtime libraries to produce the final native binary (ELF, Mach‑O, or PE). TypePHP implements only the prepare and convert stages; the compile and build stages are delegated to the mature C++ toolchain.
02. Conversion Stage: PHP → C++ Mapping
Conversion maps each PHP construct to C++ according to two type layers.
Native Types (enabled with use native_types) map to php::Int, php::Float, php::Bool (int64_t/double/bool). An int compiled with native types becomes a raw int64_t with no boxing.
Dynamic Types (default, no declaration) map to php::Var (zval wrapper), php::Array, php::String, php::Object. Without native types, an int remains a boxed zval.
Mapping rules:
PHP function → C++ function (direct C++ calls, virtual dispatch when overridden).
PHP class → C++ class (properties laid out at fixed offsets).
Built‑in functions → direct calls to the underlying C function via zend_call_function().
Parts that cannot be determined statically retain runtime dynamic capability.
Generate the C++ without invoking the compiler: tpc hello.php --dry The command creates C++ files in the build directory, showing how an echo becomes a call to the phpx runtime and how a typed loop translates to a clean C++ while loop. The output directory can be changed, e.g.:
tpc project.yml --dry --build-dir /tmp/typephp-build03. C++ Compilation
Key parameters for the system compiler:
Optimization level : -O0 (debug) to -O3. The --debug flag maps to -O0; release builds typically use -O2 or -O3 for benchmarking.
Parallel compilation : -j8 speeds up large projects.
Compiler selection : specify in project.yml, e.g. cpp-compiler: clang++.
C++ standard : default c++20, configurable via cxx-std: c++20.
Hot/Cold annotations are translated to __attribute__((hot)) or __attribute__((cold)), influencing optimizer decisions.
04. Linking
Object files are linked with two core runtime libraries:
libphp.so : provides built‑in functions and ZendVM fallback execution.
libphpx.so : TypePHP runtime offering native types, containers, and high‑precision math.
The linked product is a native binary appropriate for the target OS (ELF, Mach‑O, or PE).
05. Runtime Execution Modes
TypePHP programs run in a hybrid environment with three cooperative modes:
Mode 1 – Static AOT Execution : Ahead‑of‑time compiled user code runs as pure machine instructions, eliminating zval boxing and opcode dispatch for near‑C++ performance.
Mode 2 – Direct ZendAPI Calls : Built‑in and extension functions are invoked via zend_call_function(), bypassing the opcode engine; overhead is limited to function‑pointer lookup and zval argument handling.
Mode 3 – ZendVM Interpretation : Constructs such as include(), require(), eval(), dynamic class definitions, and create_function() follow the full parse‑compile‑interpret pipeline, matching standard PHP performance.
Traits defined in TypePHP exist only as compile‑time AST templates and are not registered with ZendVM, so they cannot be used dynamically.
06. Entry‑Point Convention
Native binaries require a C‑style main() entry. TypePHP translates a user‑defined function main(int $argc, array $argv): void into the actual program entry, exposing $argc and $argv for command‑line arguments.
function main(int $argc, array $argv): void {
echo "Argument count: $argc
";
}07. Caching and Incremental Compilation
TypePHP caches compilation results; modifying a single file triggers incremental recompilation. Force a full rebuild with: tpc project.yml --force The --profile flag forces recompilation of main.cc to inject profiler calls.
08. Summary
The pipeline consists of four stages: prepare → convert → compile → build, producing a native binary.
TypePHP handles only translation; optimization is delegated to GCC/Clang/MSVC.
The --dry flag reveals the generated C++ source, useful for learning and debugging.
Compilation and interpretation coexist; ZendVM provides compatibility while AOT offers near‑C++ performance.
The native main() entry makes CLI development zero‑overhead.
References
Execution process: https://www.swoole.com/aot/docs/execution
Compile project: https://www.swoole.com/aot/docs/compile
Printer: https://www.swoole.com/aot/docs/printer
Command‑line options: https://www.swoole.com/aot/docs/options
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Tech Hub
Sharing cutting-edge internet technologies and practical AI resources.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
