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 likeint,float,bool, andbigintgetNativeType()– 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
- Directive Activation: The
use native_typesstatement insrc/Resolver/DeclarationSymbolTrait.phpsets$this->nativeTypesto true, triggering native ABI generation. - Type Classification:
src/Parser/TypeDetectionTrait.phpprovidesisNativeType()andgetNativeType()to map PHP scalars to C++ primitives. - Zero-Cost Operations: Binary and assignment operations in
BinaryOpTrait.phpemit direct C++ arithmetic when native types are enabled. - Boundary Optimization:
ParameterValidationLowering.phppasses unboxed scalars to functions and validates strict typing only at entry points. - Native Objects:
NativeClassAttributeLowering.phpgenerates C++ structs with$classDef->nativeObjectmarking, whileNativeTypeCompatibilityTrait.phpenforces ABI safety constraints.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →