Fundamentals 11 min read

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.

Open Source Tech Hub
Open Source Tech Hub
Open Source Tech Hub
How TypePHP Eliminates Interpretation: A Deep Dive into Its Compilation Process

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-build

03. 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: prepareconvertcompilebuild, 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

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CLICompilationC++AOTTypePHP
Open Source Tech Hub
Written by

Open Source Tech Hub

Sharing cutting-edge internet technologies and practical AI resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.