C++ Equivalents for PHP Scalar Types When Using `use native_types` in TypePHP
When you enable use native_types in TypePHP, scalar PHP types int, float, and bool compile directly to C++ php::Int, php::Float, and php::Bool for high-performance execution, while high-precision types like bigInt and decimal use boxed php::Var wrappers around GMP and libmpdec.
The use native_types directive in the swoole/typephp repository triggers the AOT compiler to bypass the traditional ZVAL abstraction for specific PHP scalars, emitting native C++ arithmetic operations instead. This approach reduces memory overhead and eliminates dynamic type-checking overhead for numeric-intensive workloads. Understanding the exact mapping between PHP type declarations and their C++ equivalents is essential for optimizing performance-critical applications.
Native Scalar Type Mappings
The following PHP scalar types receive direct C++ equivalents when native types are enabled, bypassing the Zend virtual machine's zval container.
Integer and Floating-Point Types
The PHP int type compiles to php::Int, which is implemented as zend_long (an 8-byte signed integer, typically int64_t). The PHP float type becomes php::Float, backed by the C++ double type (8 bytes).
These types reside in the php namespace defined in src/phpx.h. The compiler generates straight C++ arithmetic instructions without ZVAL indirection, resulting in single-instruction addition or multiplication rather than function calls into the Zend engine.
Boolean Types
The PHP bool type maps to php::Bool, implemented as the C++ primitive bool (1 byte). Unlike traditional PHP where booleans reside inside zval containers with type tags, native booleans use standard processor registers and memory layouts, enabling branch prediction optimizations and reducing memory footprint by 7x compared to ZVAL-based storage.
High-Precision and Boxed Numeric Types
PHP's dynamic precision limitations are addressed through high-precision numeric types that, while native to C++ libraries, remain boxed within the PHP runtime's variant system.
BigInt, Decimal, and BigFloat Implementation
Three high-precision types are supported but use a different compilation strategy:
bigIntcompiles tophp::Var(Box<BigInt>), wrapping GMP'smpz_class(~32 bytes+)decimalcompiles tophp::Var(Box<Decimal>), wrapping libmpdec'sDecimal(~64 bytes+)bigFloatcompiles tophp::Var(Box<BigFloat>), wrapping MPFR'smpfr_t(~32 bytes+)
These types are defined in src/phpx_big_int.h, src/phpx_decimal.h, and src/phpx_big_float.h respectively. While they cannot use raw C++ register arithmetic due to their arbitrary precision requirements, they avoid PHP's string-based number handling by interfacing directly with high-performance mathematical libraries.
Type Semantics and Compilation Rules
The TypePHP compiler enforces strict semantics when mixing native types to maintain performance guarantees.
Arithmetic Behavior and Type Coercion
Native-type arithmetic follows pure C++ semantics. For example, the operation int += float truncates the float to an integer before addition, unlike PHP's standard behavior of converting the integer to float and performing floating-point addition. This behavior is documented in docs/en/NATIVE_TYPES.md.
High-precision types cannot be combined with ordinary scalars without explicit conversion. Attempting to add a php::Int directly to a bigInt triggers a compile-time error, requiring developers to use explicit constructor calls like std::bigInt($value).
Object Property Constraints
Object properties declared with native scalar types are fixed-type for the object's lifetime. A property declared as public int $value cannot be unset or assigned null unless explicitly marked nullable with ?int. This constraint allows the compiler to reserve exactly 8 bytes for the property in the object layout, eliminating the overhead of hash table lookups for property access.
Practical Code Examples
Simple arithmetic operations compile to direct C++ instructions:
<?php
use native_types;
function add(int $a, int $b): int {
return $a + $b; // Compiles to php::Int addition (int64_t)
}
function mix(int $i, float $f): float {
return $i + $f; // Both operands promoted to php::Float (double)
}
The generated C++ implementation eliminates all ZVAL manipulation:
php::Int add(php::Int a, php::Int b) {
return a + b; // Direct int64_t addition
}
php::Float mix(php::Int i, php::Float f) {
return static_cast<double>(i) + f; // Double addition
}
High-precision types require wrapper calls while maintaining mathematical accuracy:
<?php
use native_types;
$big = std::bigInt("123456789012345678901234567890");
$dec = std::decimal("12345.6789");
$flt = std::bigFloat(3.1415926535);
$sum = $big + $big; // → php::BigInt::add(...)
$ratio = $dec / std::decimal("2"); // → php::Decimal::div(...)
$pi2 = $flt * std::bigFloat(2); // → php::BigFloat::mul(...)
Object properties enforce type constraints at compile time:
<?php
use native_types;
class Counter {
public int $value = 0; // Fixed-type native int
}
$cnt = new Counter();
$cnt->value = 5; // OK
// $cnt->value = null; // ❌ Compile error – cannot change int to null
Reference Implementation and Source Files
According to the swoole/typephp source code, the following files define the type system architecture:
docs/en/NATIVE_TYPES.md— Official documentation specifying the PHP-to-C++ type mapping and semantic rulessrc/phpx.h— Definesphp::Int,php::Float,php::Bool, and thephp::Variantwrapper class used for boxed typessrc/phpx_big_int.h— C++ wrapper around GMP providing theBox<BigInt>implementationsrc/phpx_decimal.h— C++ wrapper around libmpdec providing theBox<Decimal>implementationsrc/phpx_big_float.h— C++ wrapper around MPFR providing theBox<BigFloat>implementation
Summary
- Native scalars: PHP
int,float, andboolmap tophp::Int,php::Float, andphp::Bool(C++int64_t,double, andbool), eliminating ZVAL overhead. - Boxed precision:
bigInt,decimal, andbigFloatusephp::Varwrappers around GMP, libmpdec, and MPFR libraries for arbitrary precision arithmetic. - C++ semantics: Native-type arithmetic follows C++ rules (e.g., truncation on mixed int/float operations), not PHP's dynamic juggling.
- Fixed properties: Object properties with native types cannot be reassigned to incompatible types or null unless explicitly nullable.
- Documentation: Detailed mapping specifications reside in
docs/en/NATIVE_TYPES.mdwithin the swoole/typephp repository.
Frequently Asked Questions
What happens to PHP strings and arrays when using use native_types?
Standard PHP types including string, array, object, and mixed continue to use the traditional ZVAL-based representations (php::Str, php::Array, php::Object, php::Var). Only the scalar numeric types and booleans receive the native C++ optimization treatment.
Can I mix native int types with high-precision bigInt in arithmetic operations?
No, the TypePHP compiler raises a compile-time error when attempting to mix native scalars with high-precision types directly. You must explicitly convert native types using constructors like std::bigInt($nativeInt) before performing arithmetic between these categories.
Does use native_types change the memory layout of PHP objects?
Yes, object properties declared with native scalar types are stored as fixed-size C++ primitives (8 bytes for int/float, 1 byte for bool) directly in the object structure, rather than as pointers to zval containers. This reduces memory usage and improves cache locality for numeric-heavy classes.
Where is the complete type mapping documented?
The canonical reference for all PHP-to-C++ type mappings and semantic rules is located at docs/en/NATIVE_TYPES.md in the swoole/typephp repository. This file specifies the behavior of arithmetic operations, nullable type syntax, and integration with the underlying GMP, libmpdec, and MPFR libraries.
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 →