How TypePHP Handles Native Types with `use native_types`

TypePHP toggles a global native-type compilation mode via the use native_types directive, which eliminates zval boxing by mapping PHP scalars directly to C++ ABI types throughout the compiler pipeline.

TypePHP is a transpiler that compiles PHP to native C++ for the Swoole ecosystem. When developers declare use native_types in a script, the parser sets an internal $this->nativeTypes flag that propagates through every subsequent compiler phase, enabling zero-cost abstractions for scalar operations.

How the use native_types Directive Activates the Compiler

The native type system begins in the declaration parsing phase. When the tokenizer encounters the use native_types statement, the resolver immediately flips a boolean flag that persists for the remainder of the compilation unit.

Detection in DeclarationSymbolTrait.php

In src/Resolver/DeclarationSymbolTrait.php, the parser analyzes use declarations to detect the native types directive. Upon recognition, it assigns $this->nativeTypes = true, signaling to all downstream transforms that scalar types should be treated as native C++ primitives rather than PHP zval containers.

This flag check appears in the compiler base and throughout the transformation pipeline, allowing conditional emission of native ABI code versus generic Zend VM compatible code.

Native Type Detection and Mapping

Once the flag is set, the compiler must distinguish between native scalars and standard PHP types. This classification determines whether a variable requires heap allocation or can reside in CPU registers.

TypeDetectionTrait.php Implementation

The src/Parser/TypeDetectionTrait.php file provides the core classification logic through two key methods:

  • isNativeType() – Returns true for scalars like int, float, bool, and bigint
  • getNativeType() – Maps PHP type names to their corresponding C++ ABI equivalents (e.g., int → int, float → double)

These helpers are invoked during AST construction to annotate type nodes with native classification metadata, enabling later optimizer passes to skip zval boxing logic.

Code Generation Optimizations

With native type detection enabled, multiple compiler components bypass generic PHP runtime overhead and emit direct native arithmetic and memory operations.

Arithmetic and Assignment Operations

In src/Transform/BinaryOpTrait.php and src/Transform/AssignOpTrait.php, the compiler checks $this->nativeTypes before emitting code. When the flag is true and both operands are classified as native scalars, the transform emits direct C++ arithmetic (e.g., a + b) instead of zval addition helpers. This eliminates function call overhead and enables LLVM/SIMD optimizations during the final C++ compilation phase.

Function Calls and Parameter Validation

The src/Transform/ParameterValidationLowering.php component generates argument conversion routines that pass scalars directly to functions without boxing. For strict scalar typing, it inserts genStrictScalarArgConversion checks that validate types at the boundary before passing raw int, double, or bool values into the function body.

Similarly, src/Optimizer/FuncCallOptimizer.php leverages the native type flag to skip zval allocation for return values, allowing functions to return primitives directly to callers.

Native Classes and Object Handling

The native type system extends beyond scalars to support entire classes that exist outside the Zend VM heap, enabling high-performance data structures that interoperate with C++ libraries.

NativeClassAttributeLowering.php

When processing class declarations, src/Transform/NativeClassAttributeLowering.php marks qualifying classes with $classDef->nativeObject = true. Native classes can contain only native-typed properties and methods, ensuring that instances occupy contiguous memory without zval indirection. The lowering pass generates C++ struct definitions and accessor methods that map directly to the underlying native layout.

NativeTypeCompatibilityTrait.php

The src/TypeSystem/NativeTypeCompatibilityTrait.php enforces safety invariants across the type system. It provides getReturnType() resolution for native signatures and isNativeObjectClass() checks that prevent illegal cross-boundary inheritance—specifically, ensuring that native objects never extend or implement non-native PHP interfaces, which would violate ABI compatibility.

Practical Compilation Example

Consider a script that leverages the native type system for mathematical operations:

<?php
use native_types;

function calculate(int $x, float $y): float {
    return $x * $y + 2.5;
}

native class Point {
    public native int $x;
    public native int $y;
    
    public native function distance(Point $other): float;
}
?>

When use native_types is active, TypePHP generates C++ code that bypasses the Zend VM entirely:

double calculate(int x, double y) {
    return (x * y) + 2.5;  // Direct register arithmetic, no zval allocation
}

struct Point {
    int x;
    int y;
    
    double distance(const Point& other) {
        // Native C++ implementation accessing members directly
        return std::hypot(x - other.x, y - other.y);
    }
};

Without the directive, the same PHP code would compile to zval-centric implementations using ZVAL_LONG, ZVAL_DOUBLE, and zend_function call overhead, incurring significant memory indirection and CPU cache pressure.

Summary

Frequently Asked Questions

What PHP types qualify as native types in TypePHP?

TypePHP recognizes int, float, bool, and bigint as native scalars when use native_types is declared. These map directly to C++ int, double, bool, and 64-bit integer types respectively, residing on the stack or in CPU registers rather than the Zend heap.

Can native classes extend regular PHP classes?

No. According to src/TypeSystem/NativeTypeCompatibilityTrait.php, native classes marked with $classDef->nativeObject = true cannot extend or implement non-native PHP types. This restriction prevents ABI violations where a native struct layout would be incompatible with zval expectations in the Zend VM.

Does use native_types affect function argument validation?

Yes. The src/Transform/ParameterValidationLowering.php component consults the $this->nativeTypes flag to generate genStrictScalarArgConversion guards. When active, arguments are validated once at the function boundary and then passed as raw C++ primitives, eliminating repetitive type checks and zval extraction inside the function body.

What happens if I omit use native_types in a script?

Without the directive, TypePHP defaults to standard PHP semantics where all values are represented as zval structures. The compiler ignores native type hints for ABI purposes, generating code that interacts with the Zend VM's heap and reference counting, which provides full PHP compatibility at the cost of performance.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →