37 KiB
AOT Compiler Universal Methods Tutorial
This tutorial comprehensively introduces the AOT compiler's Universal Methods system—a mechanism for zero-overhead method calls on native types using the $value->method() syntax.
Table of Contents
- What Are Universal Methods
- Design Principles
- Supported Types Overview
- Int Integer Methods
- Float Floating-Point Methods
- Bool Boolean Methods
- String Methods
- Array Methods
- Stream Methods
- Big* High-Precision Type Methods
- Method Chaining
- Mutable vs Immutable Methods
- Var Type Method Lookup
- Extension Methods: Auto Discovery
- Complete Examples
1. What Are Universal Methods
Universal Methods allow you to call methods directly on variables of PHP native types, just like calling methods on objects. At compile time, the compiler translates these method calls into the corresponding C function or C++ method calls, generating zero-overhead native code.
// Call methods directly on a string
$s = "hello world";
echo $s->length(); // → strlen($s) → 11
echo $s->upper(); // → strtoupper($s) → "HELLO WORLD"
echo $s->substr(0, 5); // → substr($s, 0, 5) → "hello"
// Call methods directly on an array
$arr = [1, 3, 5, 7, 9];
echo $arr->count(); // → count($arr) → 5
echo $arr->contains(3); // → in_array(3, $arr) → true
$arr->push(11); // → array_push($arr, 11)
// Call methods directly on an integer
$a = 100;
$a->add(50); // → a += 50 → 150
echo $a->toString(); // → "150"
// Call methods directly on high-precision types
$big = std::bigInt("12345678901234567890");
echo $big->mul(2)->toString(); // → "24691357802469135780"
Key idea: All universal method calls are fully resolved into direct function calls at compile time. There is no vtable lookup, reflection, or runtime type checking—the generated C++ code is exactly equivalent to hand-written C function calls.
2. Design Principles
2.1 Compile-Time Resolution
Each universal method call goes through the following steps at compile time:
- Type inference: The compiler infers the type of the receiver (Int / Float / String / Array / Stream / BigInt / Decimal / BigFloat / Var)
- Method lookup: Look up the method definition in that type's method table
- Argument validation: Check that the number of arguments is within the
min_args~max_argsrange - Code generation: Generate the corresponding C/C++ call code based on the handler type
2.2 Handler Types
The universal methods system supports five internal handlers, each suited to different scenarios:
| Handler | Description | Example |
|---|---|---|
calc_op |
Directly generates C++ operator code (Int/Float only) | $a->add(1) → a + 1 |
php_fn |
Calls a PHP standard library function | $s->length() → strlen(s) |
cpp_fn |
Calls a phpx C++ static method |
$big->add(1) → BigInt::add($big, 1) |
direct_method |
Calls a Variant C++ member method | $s->equals("x") → s.equals("x") |
convert_fn |
Type conversion | $a->toFloat() → php::toFloat(a) |
php_fn_ref |
Calls a PHP function and modifies the original value by reference (Array only) | $arr->push(1) → array_push($arr, 1) |
direct_method_mutate |
Calls a mutating Variant member method | $arr->set(0, 1) → arr.set(0, 1) |
3. Supported Types Overview
| Type | Method Count | Main Categories |
|---|---|---|
| Int | 26 | Arithmetic, math functions, type conversion |
| Float | 26 | Arithmetic, math functions, trigonometric functions, type conversion |
| Bool | 2 | Type conversion |
| String | 70+ | String operations, search, encoding, Hash, multibyte, serialization |
| Array | 50+ | CRUD, sorting, traversal, set operations, serialization |
| Stream | 30+ | Read/write, seeking, locking, Socket, filters |
| BigInt | 14 | Arithmetic, comparison, conversion, GCD |
| Decimal | 11 | Arithmetic, comparison, conversion |
| BigFloat | 10 | Arithmetic, comparison, conversion |
4. Int Integer Methods
4.1 Arithmetic Operations (Return Int)
$a = 100;
$a->add(50); // a += 50 → 150
$a->sub(30); // a -= 30 → 70
$a->mul(2); // a *= 2 → 200
$a->div(4); // a /= 4 → 25
$a->mod(7); // a %= 7 → 2
$a->inc(); // a++ → 101
$a->dec(); // a-- → 100
Mutability:
add/sub/mul/div/mod/inc/decmodify the original variable (directly operating on the C++ nativeint64_t), while also returning the new value. This differs from the immutable semantics of the Big* types.
$a = 100;
$b = $a->add(50); // $a becomes 150, $b is also 150 (returns the new value)
4.2 Math Functions
$a = -100;
$a->abs(); // abs($a) → 100
$a->ceil(); // ceil($a) → -100.0 (float)
$a->floor(); // floor($a) → -100.0 (float)
$a->round(); // round($a) → -100.0 (float)
$a->sqrt(); // sqrt($a) → NaN (no real square root for a negative number)
$a->pow(3); // $a ** 3 → -1000000
$a->log(); // log($a) → NaN
$a->log10(); // log10($a) → NaN
$a->exp(); // exp($a) → 3.72e-44 (float)
$a->max(50); // max($a, 50) → 50
$a->min(50); // min($a, 50) → -100
Note:
ceil,floor, androundreturn a Float type (standard PHP behavior).powreturns a Var type (because the result of exponentiation may overflow).
4.3 Trigonometric Functions
$a = 0;
$a->sin(); // sin(0) → 0.0
$a->cos(); // cos(0) → 1.0
$a->tan(); // tan(0) → 0.0
$a->asin(); // asin(0) → 0.0
$a->acos(); // acos(1) → 0.0
$a->atan(); // atan(0) → 0.0
$a->atan2(1); // atan2(0,1) → 0.0
$a->deg2rad(); // deg2rad(0) → 0.0
$a->rad2deg(); // rad2deg(0) → 0.0
4.4 Type Conversion
$a = 42;
$a->toFloat(); // (float) $a → 42.0
$a->toString(); // (string) $a → "42"
$a->toBool(); // (bool) $a → true
4.5 Complete Method List
| Method | Args | Return Type | Description |
|---|---|---|---|
add($x) |
1 | Int | Addition (modifies the original value) |
sub($x) |
1 | Int | Subtraction (modifies the original value) |
mul($x) |
1 | Int | Multiplication (modifies the original value) |
div($x) |
1 | Int | Division (modifies the original value) |
mod($x) |
1 | Int | Modulo (modifies the original value) |
inc() |
0 | Int | Increment (modifies the original value) |
dec() |
0 | Int | Decrement (modifies the original value) |
abs() |
0 | Int | Absolute value |
ceil() |
0 | Float | Round up |
floor() |
0 | Float | Round down |
round() |
0-2 | Float | Round to nearest |
sqrt() |
0 | Float | Square root |
pow($x) |
1 | Var | Exponentiation |
log() |
0-1 | Float | Natural logarithm |
log10() |
0 | Float | Base-10 logarithm |
exp() |
0 | Float | Exponential of e |
sin() |
0 | Float | Sine |
cos() |
0 | Float | Cosine |
tan() |
0 | Float | Tangent |
asin() |
0 | Float | Arcsine |
acos() |
0 | Float | Arccosine |
atan() |
0 | Float | Arctangent |
atan2($x) |
1 | Float | Two-argument arctangent |
deg2rad() |
0 | Float | Convert degrees to radians |
rad2deg() |
0 | Float | Convert radians to degrees |
max($x) |
1 | Int/Float | Maximum value |
min($x) |
1 | Int/Float | Minimum value |
toFloat() |
0 | Float | Convert to float |
toString() |
0 | String | Convert to string |
toBool() |
0 | Bool | Convert to boolean |
5. Float Floating-Point Methods
Float's method set is almost identical to Int's, but the return type is Float (ceil/floor/round/trigonometric functions, etc. are still Float).
$f = 3.14;
$f->add(1.0); // f += 1.0 → 4.14
$f->sub(1.0); // f -= 1.0 → 2.14
$f->mul(2.0); // f *= 2.0 → 6.28
$f->div(2.0); // f /= 2.0 → 1.57
$f->abs(); // abs(3.14) → 3.14
$f->sqrt(); // sqrt(3.14) → 1.772...
$f->sin(); // sin(3.14) → 0.00159...
$f->round(2); // round(3.14, 2) → 3.14
// Float-specific conversions
$f->toInt(); // (int) $f → 3
$f->toString(); // (string) $f → "3.14"
$f->toBool(); // (bool) $f → true
The main differences between Float and Int methods:
- Int has
mod($x), Float does not (floating-point modulo is meaningless) - Arithmetic methods operate directly on C++
double, with performance identical to hand-written C code
6. Bool Boolean Methods
The Bool type has only two conversion methods:
$b = true;
$b->toInt(); // (int) $b → 1
$b->toString(); // (string) $b → "1"
7. String Methods
String has the richest method set, covering most string operation needs in daily development.
7.1 Basic Operations
$s = "hello world";
$s->length(); // strlen($s) → 11
$s->isEmpty(); // empty($s) → false
$s->upper(); // strtoupper($s) → "HELLO WORLD"
$s->lower(); // strtolower($s) → "hello world"
$s->upperFirst(); // ucfirst($s) → "Hello world"
$s->lowerFirst(); // lcfirst($s) → "hello world"
$s->upperWords(); // ucwords($s) → "Hello World"
$s->trim(); // trim($s) → "hello world"
$s->lTrim(); // ltrim($s) → "hello world"
$s->rTrim(); // rtrim($s) → "hello world"
$s->trim(" \t\n\r"); // trim($s, chars)
7.2 Search and Comparison
$s = "hello world";
// Checking
$s->startsWith("hello"); // str_starts_with(...) → true
$s->endsWith("world"); // str_ends_with(...) → true
$s->contains("lo wo"); // str_contains(...) → true
$s->compare("hello"); // strcmp(...) → >0
$s->iCompare("HELLO"); // strcasecmp(...) → 0
$s->isNumeric(); // is_numeric(...) → false
// Position lookup
$s->indexOf("world"); // strpos($s, "world") → 6
$s->lastIndexOf("o"); // strrpos($s, "o") → 7
$s->iIndexOf("WORLD"); // stripos($s, "WORLD") → 6
$s->iLastIndexOf("O"); // strripos($s, "O") → 7
// Content lookup
$s->find("world"); // strstr($s, "world") → "world"
$s->iFind("WORLD"); // stristr($s, "WORLD") → "world"
$s->lastCharIndexOf("o"); // strrchr($s, "o") → "orld"
7.3 Substring and Replacement
$s = "hello world";
// Substring
$s->substr(0, 5); // substr($s, 0, 5) → "hello"
$s->substr(6); // substr($s, 6) → "world"
// Counting
$s->substrCount("l"); // substr_count($s, "l") → 3
$s->wordCount(); // str_word_count($s) → 2
// Replacement
$s->replace("hello", "hi"); // str_replace("hello", "hi", $s)
$s->iReplace("HELLO", "hi"); // str_ireplace(...)
$s->substrReplace("hi", 0, 5); // substr_replace($s, "hi", 0, 5)
$s->stripTags(); // strip_tags($s)
$s->stripTags("<br><p>"); // strip_tags($s, tags)
7.4 Splitting and Joining
$s = "hello world";
// Split
$words = $s->split(" "); // explode(" ", $s) → ["hello", "world"]
$words->count(); // 2
// Join (operates on an array)
$words->join(", "); // implode(", ", $words) → "hello, world"
// Repeat
$s->repeat(3); // str_repeat($s, 3) → "hello worldhello worldhello world"
// Pad
$s->pad(20, "-"); // str_pad($s, 20, "-")
7.5 Encoding and Escaping
$s = "hello world & <test>";
$s->htmlEntityEncode(); // htmlentities($s)
$s->htmlEntityDecode(); // html_entity_decode($s)
$s->htmlSpecialCharsEncode(); // htmlspecialchars($s)
$s->htmlSpecialCharsDecode(); // htmlspecialchars_decode($s)
$s->urlEncode(); // urlencode($s) → "hello+world+%26+%3Ctest%3E"
$s->urlDecode(); // urldecode($s)
$s->rawUrlEncode(); // rawurlencode($s)
$s->rawUrlDecode(); // rawurldecode($s)
$s->addSlashes(); // addslashes($s)
$s->stripSlashes(); // stripslashes($s)
$s->addCSlashes("A..z"); // addcslashes($s, "A..z")
$s->stripCSlashes(); // stripcslashes($s)
$s->base64Encode(); // base64_encode($s)
$s->base64Decode(); // base64_decode($s)
7.6 Hash and Checksum
$s = "hello";
$s->md5(); // md5($s) → "5d41402abc4b2a76b9719d911017c592"
$s->sha1(); // sha1($s) → "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"
$s->crc32(); // crc32($s) → 907060870
$s->hash("sha256"); // hash("sha256", $s) → "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
$s->hashCode(); // C++ std::hash → hash value (int)
7.7 Regular Expression Matching
$s = "hello world";
// match(pattern) → returns the match array
$result = $s->match("/hello/");
// matchAll(pattern) → returns all match results
$results = $s->matchAll("/[a-z]+/");
7.8 Serialization
$s = '{"name":"John","age":30}';
$data = $s->jsonDecode(); // json_decode($s, true) → ["name" => "John", ...]
$obj = $s->jsonDecodeToObject(); // json_decode($s) → stdClass
$s = 'a:3:{i:0;s:3:"foo";i:1;s:3:"bar";i:2;s:3:"baz";}';
$arr = $s->unserialize(); // unserialize($s) → ["foo", "bar", "baz"]
7.9 Multibyte Strings (mbstring)
Methods with the mb prefix correspond to PHP's mb_* function family:
$s = "你好世界";
$s->mbLength(); // mb_strlen($s) → 4
$s->mbUpper(); // mb_strtoupper($s)
$s->mbLower(); // mb_strtolower($s)
$s->mbSubstr(0, 2); // mb_substr($s, 0, 2) → "你好"
$s->mbIndexOf("世界"); // mb_strpos($s, "世界") → 2
$s->mbFind("世"); // mb_strstr($s, "世")
$s->mbDetectEncoding(); // mb_detect_encoding($s)
$s->mbConvertEncoding("UTF-8"); // mb_convert_encoding($s, "UTF-8")
$s->mbConvertCase(MB_CASE_TITLE); // mb_convert_case($s, MB_CASE_TITLE)
$s->mbTrim(); // mb_trim($s)
$s->mbLTrim(); // mb_ltrim($s)
$s->mbRTrim(); // mb_rtrim($s)
7.10 C++ Native Methods
The following methods directly call C++ member functions of phpx::Variant, with no corresponding PHP function:
$s = "hello";
$s->equals("hello"); // C++ String.equals() — value comparison
$s->append(" world"); // C++ String.append() — append (modifies the original value)
8. Array Methods
Array methods are divided into read-only methods and mutating methods. Mutating methods directly modify the original array variable.
8.1 Basic Information
$arr = [1, 3, 5, 7, 9];
$arr->count(); // count($arr) → 5
$arr->isEmpty(); // empty($arr) → false
$arr->isList(); // array_is_list($arr) → true
8.2 CRUD
$arr = [1, 2, 3];
// Mutating methods (modify the original array)
$arr->push(4); // array_push($arr, 4) → [1,2,3,4]
$arr->push(5, 6, 7); // supports multiple arguments
$arr->pop(); // array_pop($arr) → returns 7
$arr->shift(); // array_shift($arr) → returns 1
$arr->unshift(0); // array_unshift($arr, 0) → [0,...]
$arr->set(0, 100); // C++ Array.set(0, 100) → [100,...]
$arr->del(0); // C++ Array.del(0) → removes index 0
$arr->clean(); // C++ Array.clean() → []
// Read-only methods
$arr = ['a' => 1, 'b' => 2, 'c' => 3];
$arr->get('a'); // C++ Array.get('a') → 1
$arr->keyExists('a'); // array_key_exists('a', $arr) → true
$arr->contains(2); // in_array(2, $arr) → true
$arr->search(2); // array_search(2, $arr) → "b"
8.3 Traversal and Aggregation
$arr = [1, 3, 5, 7, 9];
$arr->sum(); // array_sum($arr) → 25
$arr->product(); // array_product($arr) → 945
$arr->all(fn($v) => ...); // array_all($arr, fn)
$arr->any(fn($v) => ...); // array_any($arr, fn)
$arr->map(fn($v) => $v * 2);// array_map(fn, $arr) → [2,6,10,14,18]
$arr->reduce(fn($c, $v) => $c + $v, 0); // array_reduce($arr, fn, 0)
$arr->filter(fn($v) => $v > 5); // array_filter($arr, fn)
$arr->walk(fn(&$v) => $v *= 2); // array_walk($arr, fn)
8.4 Sorting
$arr = [3, 1, 4, 1, 5, 9];
$arr->sort(); // sort($arr) → [1,1,3,4,5,9]
$arr->sortDesc(); // rsort($arr) → [9,5,4,3,1,1]
$arr->keySort(); // ksort($arr) → sort by key
$arr->valueSort(); // asort($arr) → sort by value (preserving keys)
All sorting methods modify the original array.
8.5 Set Operations
$a = [1, 2, 3, 4, 5];
$b = [4, 5, 6, 7, 8];
$a->diff($b); // array_diff($a, $b) → [1,2,3]
$a->intersect($b); // array_intersect(...) → [4,5]
$a->merge($b); // array_merge($a, $b) → [1,2,3,4,5,4,5,6,7,8]
$a->unique(); // array_unique($a) → [1,2,3,4,5]
$a->flip(); // array_flip($a) → {1:0, 2:1, 3:2, ...}
$a->reverse(); // array_reverse($a) → [5,4,3,2,1]
$a->replace($b); // array_replace($a, $b)
$a->values(); // array_values($a) → re-index
$a->combine($keys); // array_combine($keys, $a)
$a->fillKeys($value); // array_fill_keys($a, $value)
Methods such as
diff,intersect,merge, andreplacesupport variadic arguments:$a->merge($b, $c, $d)can merge multiple arrays at once.
8.6 Extraction and Slicing
$arr = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5];
$arr->keys(); // array_keys($arr) → ['a','b','c','d','e']
$arr->slice(1, 3); // array_slice($arr, 1, 3) → ['b'=>2, 'c'=>3, 'd'=>4]
$arr->chunk(2); // array_chunk($arr, 2) → [[1,2],[3,4],[5]]
$arr->column('name'); // array_column($arr, 'name')
$arr->splice(1, 3, [6,7]); // array_splice($arr, 1, 3, [6,7]) — modifies the original array
$arr->rand(2); // array_rand($arr, 2)
$arr->keyFirst(); // array_key_first($arr) → "a"
$arr->keyLast(); // array_key_last($arr) → "e"
$arr->find(fn($v) => $v > 3); // array_find($arr, fn)
8.7 String-Related
$arr = ["hello", "world"];
$arr->join(", "); // implode(", ", $arr) → "hello, world"
$arr->replaceStr("hello", "hi"); // str_replace("hello", "hi", $arr)
$arr->iReplaceStr("HELLO", "hi"); // str_ireplace(...)
8.8 Serialization
$arr = ["name" => "John", "age" => 30];
$arr->serialize(); // serialize($arr) → "a:2:{...}"
$arr->marshal(); // serialize($arr) — alias
$arr->jsonEncode(); // json_encode($arr) → '{"name":"John","age":30}'
8.9 Type Conversion
$arr = [1, 2, 3];
$arr->toInt(); // (int) non-empty array → 1
$arr->toFloat(); // (float) non-empty array → 1.0
$arr->toBool(); // (bool) non-empty array → true
$arr->toString(); // → "Array"
8.10 Complete Method Category Table
| Category | Methods |
|---|---|
| Basic information | count, isEmpty, isList |
| CRUD | push, pop, shift, unshift, set, get, del, clean, keyExists, contains, search |
| Traversal & aggregation | sum, product, all, any, map, reduce, filter, walk |
| Sorting | sort, sortDesc, keySort, valueSort |
| Set operations | diff, diffAssoc, diffKey, intersect, intersectAssoc, merge, unique, flip, reverse, replace, values, combine, fillKeys |
| Extraction & slicing | keys, slice, chunk, column, splice, rand, keyFirst, keyLast, find |
| String | join, replaceStr, iReplaceStr, countValues, pad |
| Serialization | serialize, marshal, jsonEncode |
| Type conversion | toInt, toFloat, toBool, toString |
9. Stream Methods
The Stream type represents a file handle or network connection. Obtain it via functions such as fopen().
9.1 Read and Write
$fp = fopen("test.txt", "w+");
$fp->write("hello world\n"); // fwrite($fp, "hello world\n") → number of bytes written
$fp->write("more data", 4); // fwrite($fp, "more data", 4) → writes only 4 bytes
$fp->seek(0); // fseek($fp, 0) → back to the beginning
$content = $fp->read(1024); // fread($fp, 1024)
$content = $fp->getContents(); // stream_get_contents($fp)
$char = $fp->getChar(); // fgetc($fp) → reads one character
$line = $fp->getLine(); // fgets($fp) → reads one line
$line = $fp->getLine(1024); // fgets($fp, 1024)
$line = $fp->getRecord(1024, "\n"); // stream_get_line($fp, 1024, "\n")
9.2 Metadata and Status
$fp->tell(); // ftell($fp) → current position
$fp->eof(); // feof($fp) → whether at EOF
$fp->stat(); // fstat($fp) → file status array
$fp->getMetaData(); // stream_get_meta_data($fp)
$fp->isLocal(); // stream_is_local($fp)
$fp->isTTY(); // stream_isatty($fp)
9.3 Control Operations
$fp->truncate(0); // ftruncate($fp, 0) → truncates the file
$fp->sync(); // fsync($fp) → sync to disk
$fp->dataSync(); // fdatasync($fp) → sync data
$fp->close(); // fclose($fp) → close
// Locking
$fp->lock(LOCK_EX); // flock($fp, LOCK_EX)
$fp->lock(LOCK_SH); // flock($fp, LOCK_SH)
$fp->lock(LOCK_UN); // flock($fp, LOCK_UN)
// Buffer settings
$fp->setBlocking(true); // stream_set_blocking($fp, true)
$fp->setChunkSize(8192); // stream_set_chunk_size($fp, 8192)
$fp->setReadBuffer(8192); // stream_set_read_buffer($fp, 8192)
$fp->setWriteBuffer(8192); // stream_set_write_buffer($fp, 8192)
$fp->setTimeout(30); // stream_set_timeout($fp, 30)
$fp->supportsLock(); // stream_supports_lock($fp)
9.4 Socket Operations
// Server
$server = stream_socket_server("tcp://0.0.0.0:8080");
$client = $server->accept(); // stream_socket_accept($server)
$client->accept(30); // timeout of 30 seconds
// Information
$client->getSocketName(true); // stream_socket_get_name — remote address
$server->getSocketName(false); // stream_socket_get_name — local address
// Data
$client->sendTo("hello", 0, $addr); // stream_socket_sendto(...)
$client->recvFrom(1024); // stream_socket_recvfrom(...)
$client->recvFrom(1024, 0, $addr); // with address
// Control
$client->enableCrypto(true); // stream_socket_enable_crypto → enables TLS
$client->shutdown(STREAM_SHUT_RDWR); // stream_socket_shutdown(...)
// Filters
$fp->appendFilter("string.toupper"); // stream_filter_append(...)
$fp->prependFilter("string.tolower"); // stream_filter_prepend(...)
9.5 Stream Copy
$src = fopen("source.txt", "r");
$dst = fopen("dest.txt", "w");
$src->copy($dst); // stream_copy_to_stream($src, $dst)
$src->copy($dst, 4096); // specify buffer size
10. Big* High-Precision Type Methods
10.1 BigInt Methods
$a = std::bigInt("12345678901234567890");
// Arithmetic (each returns a new BigInt, leaving the original unchanged)
$b = $a->add(1); // $a + 1
$c = $a->sub(1); // $a - 1
$d = $a->mul(2); // $a * 2
$e = $a->div(10); // $a / 10
$f = $a->mod(1000000); // $a % 1000000
$g = $a->pow(3); // $a ** 3
// Unary methods
$h = $a->neg(); // -$a
$i = $a->abs(); // abs($a)
// Special methods
$j = $a->gcd(15); // gcd($a, 15)
// Comparison
$cmp = $a->cmp(100); // -1/0/1
// Type conversion
$a->toString(); // → "12345678901234567890"
$a->toInt(); // → int (may truncate)
$a->toFloat(); // → float (may lose precision)
| Method | Args | Return | Description |
|---|---|---|---|
add($x) |
1 | BigInt | Addition |
sub($x) |
1 | BigInt | Subtraction |
mul($x) |
1 | BigInt | Multiplication |
div($x) |
1 | BigInt | Integer division |
mod($x) |
1 | BigInt | Modulo |
pow($x) |
1 | BigInt | Exponentiation |
neg() |
0 | BigInt | Negation |
abs() |
0 | BigInt | Absolute value |
gcd($x) |
1 | BigInt | Greatest common divisor |
cmp($x) |
1 | Int | Comparison |
toString() |
0 | String | Convert to string |
toInt() |
0 | Int | Convert to integer |
toFloat() |
0 | Float | Convert to float |
10.2 Decimal Methods
$d = std::decimal("123.456");
$d->add(std::decimal("50.25")); // Addition
$d->sub(std::decimal("50.25")); // Subtraction
$d->mul(2); // Multiplication
$d->div(3); // Division
$d->mod(std::decimal("5.0")); // Modulo
$d->neg(); // Negation
$d->abs(); // Absolute value
$d->cmp(std::decimal("100")); // Comparison
$d->toString(); // → "123.456"
$d->toInt(); // → 123
$d->toFloat(); // → 123.456 (double)
10.3 BigFloat Methods
$bf = std::bigFloat(3.14159265);
$bf->add(1.0); // Addition
$bf->sub(1.0); // Subtraction
$bf->mul(2.0); // Multiplication
$bf->div(2.0); // Division
$bf->neg(); // Negation
$bf->abs(); // Absolute value
$bf->cmp(3.0); // Comparison → >0
$bf->toString(); // Convert to string
$bf->toInt(); // → 3
$bf->toFloat(); // → 3.14159265
Immutability: Unlike Int/Float, all methods of the Big* types return new values and do not modify the original variable. See Section 12.
11. Method Chaining
The return type of a universal method is known at compile time, so methods can be chained directly:
// String method chaining
$result = " Hello World! "
->trim()
->lower()
->substr(0, 5)
->upper();
echo $result; // "HELLO"
// Int method chaining
$result = 100
->add(50) // 150 (modifies the original variable)
->mul(3) // 450
->sub(100) // 350
->toString();
echo $result; // "350"
// BigInt method chaining (immutable, returns new values)
$result = std::bigInt("100")
->add(std::bigInt(50))
->mul(std::bigInt(3))
->toString();
echo $result; // "450"
// Cross-type method chaining
$sum = "123456789012345678901234567890"
->length(); // String.length() → Int
echo $sum; // 30
// Method chaining + final conversion
$result = std::bigInt("99999999999999999999")
->add(std::bigInt(1))
->toString();
echo "100000000000000000000 = " . $result;
Note: Each step of an Int/Float chain modifies the original variable. If you need to keep an intermediate value, save it in a temporary variable first. Big* types do not have this problem because they are immutable.
12. Mutable vs Immutable Methods
Universal methods of different types behave differently with respect to mutability:
12.1 Mutable Methods (Modify the Original Value)
Int and Float arithmetic methods operate directly on C++ native variables and modify the original value:
$a = 100;
$b = $a->add(50); // This both modifies $a (becomes 150) and returns the new value to $b
echo $a; // 150 — has been modified
echo $b; // 150
$a->inc(); // $a becomes 151
$a->dec(); // $a becomes 150
Array mutating methods modify the original array:
$arr = [1, 2, 3];
$arr->push(4); // modifies $arr → [1,2,3,4]
$arr->pop(); // modifies $arr → [1,2,3]
$arr->sort(); // modifies $arr → [1,2,3]
$arr->set(0, 100); // modifies $arr → [100,2,3]
$arr->clean(); // modifies $arr → []
12.2 Immutable Methods (Return New Values)
All methods of BigInt, Decimal, and BigFloat do not modify the original value and return a newly created object:
$a = std::bigInt(100);
$b = $a->add(50); // $a is still 100, $b is 150
$a = std::bigInt(100);
$a->add(50); // The return value is discarded! $a is still 100
Most String methods also return new values:
$s = "hello";
$upper = $s->upper(); // $s is still "hello", $upper is "HELLO"
Exception: String.append() is a mutating method (direct_method_mutate) and modifies the original string:
$s = "hello";
$s->append(" world"); // $s becomes "hello world"
12.3 Summary of Mutable Methods
| Handler type | Affected types | Examples |
|---|---|---|
calc_op |
Int, Float | add, sub, mul, div, mod, inc, dec |
direct_method_mutate |
String, Array | append, set, del, clean |
php_fn_ref |
Array | push, pop, shift, unshift, sort, sortDesc, splice, walk |
13. Var Type Method Lookup
When a variable's type is Var (the generic PHP type), the compiler searches the method tables in the following order:
String → Array → Int → Float → Bool → Stream → BigInt → Decimal → BigFloat
Once a matching method name is found, it generates the call code for that type. If not found, it falls back to dynamic method calls (via the ZendVM).
// The type of $x is Var (from a function return value, array extraction, etc.)
$x = some_func_returning_var();
// The compiler searches in order:
// 1. First looks for length in the String method table → found! → strlen($x)
echo $x->length();
// 2. First looks for contains in the String method table → found! → str_contains($x, ...)
echo $x->contains("test");
Note: If multiple types have a method with the same name, the first matched type takes precedence. For example,
toIntexists in multiple types—the lookup stops at the first matching type.
14. Extension Methods: Auto Discovery
In addition to the built-in universal methods, the compiler also supports custom extension methods. As long as a PHP function following the naming convention is defined in the current project, the compiler automatically discovers it as a universal method.
14.1 Naming Convention
Format: {type_prefix}_{snake_case_method_name}
| Type | Prefix | Example |
|---|---|---|
| Int | int_ |
int_is_prime → $a->isPrime() |
| Float | float_ |
float_normalize → $f->normalize() |
| Bool | bool_ |
bool_toggle → $b->toggle() |
| String | str_ |
str_capitalize → $s->capitalize() |
| Array | array_ |
array_flatten → $arr->flatten() |
| Stream | stream_ |
stream_rewind → $fp->rewind() |
| BigInt | bigint_ |
bigint_is_probable_prime → $a->isProbablePrime() |
| Decimal | decimal_ |
decimal_round_to → $d->roundTo() |
| BigFloat | bigfloat_ |
bigfloat_truncate → $bf->truncate() |
14.2 Implementation Example
<?php
declare(strict_types=1);
use native_types;
/**
* Extension method: determine whether an Int is prime
* Naming: type prefix int_ + snake_case method name is_prime
*/
function int_is_prime(int $n): bool {
if ($n < 2) return false;
for ($i = 2; $i * $i <= $n; $i++) {
if ($n % $i == 0) return false;
}
return true;
}
/**
* Extension method: flatten an array
* Naming: type prefix array_ + snake_case method name flatten
*/
function array_flatten(array $arr): array {
$result = [];
array_walk_recursive($arr, function($v) use (&$result) {
$result[] = $v;
});
return $result;
}
function main(): void {
// Auto discovery: int_is_prime → $n->isPrime()
$n = 97;
if ($n->isPrime()) {
echo "$n is prime\n";
}
// Auto discovery: array_flatten → $arr->flatten()
$nested = [[1, 2], [3, [4, 5]], 6];
$flat = $nested->flatten();
var_dump($flat); // [1, 2, 3, 4, 5, 6]
}
?>
14.3 Notes
- The function's first parameter is the receiver, passed in automatically from the method call
- The return type of an extension method is fixed to
Var - Define the function before calling it—the compiler discovers functions during the analysis phase and uses them during the conversion phase
- A method's camelCase naming is automatically converted to snake_case:
isPrime→is_prime,flattenNestedArray→flatten_nested_array
15. Complete Examples
15.1 String Processing Pipeline
<?php
declare(strict_types=1);
use native_types;
function main(): void {
$raw = " <h1>Hello World!</h1> \n";
$processed = $raw
->trim() // strip surrounding whitespace
->stripTags() // strip HTML tags
->lower() // convert to lowercase
->upperWords(); // capitalize the first letter of each word
echo "原始: " . $raw->jsonEncode() . "\n";
echo "处理: " . $processed . "\n";
echo "长度: " . $processed->length() . "\n";
echo "是否为数字: " . (int)$processed->isNumeric() . "\n";
}
?>
15.2 Array Data Processing
<?php
declare(strict_types=1);
use native_types;
function main(): void {
$data = [5, 2, 8, 1, 9, 3, 7];
echo "原始: " . $data->join(", ") . "\n";
// Sorting
$data->sort();
echo "排序: " . $data->join(", ") . "\n";
// Statistics
echo "数量: " . $data->count() . "\n";
echo "求和: " . $data->sum() . "\n";
echo "最小值: " . $data->get(0) . "\n";
echo "最大值: " . $data->get($data->count() - 1) . "\n";
echo "是否包含 5: " . (int)$data->contains(5) . "\n";
// Filter and map
$even = $data->filter(function($v) { return $v % 2 == 0; });
echo "偶数: " . $even->values()->join(", ") . "\n";
$doubled = $data->map(function($v) { return $v * 2; });
echo "翻倍: " . $doubled->join(", ") . "\n";
// Serialization
echo "JSON: " . $data->jsonEncode() . "\n";
}
?>
15.3 High-Precision Calculation and Chaining
<?php
declare(strict_types=1);
use native_types;
function main(): void {
// Factorial of a large integer (using compound assignment for brevity)
$n = 50;
$result = std::bigInt(1);
for ($i = 2; $i <= $n; $i++) {
$result *= $i;
}
$digits = strlen($result->toString());
echo "{$n}! has {$digits} digits\n";
// Method chaining: BigInt arithmetic + conversion
$big = std::bigInt(1000);
$val = $big->mul(3)->add(200)->sub(50)->div(10)->toString();
echo "1000 * 3 + 200 - 50 / 10 = {$val}\n";
// Decimal financial calculation
$price = std::decimal("19.99");
$qty = 5;
$taxRate = std::decimal("0.08");
$total = $price * $qty * ($taxRate->add(std::decimal(1)));
echo "总价: " . $total->toString() . "\n";
// BigFloat scientific calculation
$pi = std::bigFloat("3.14159265358979323846");
$area = $pi * 100;
echo "圆面积: " . $area->toString() . "\n";
echo "取整: " . $area->toInt() . "\n";
}
?>
15.4 File Processing
<?php
declare(strict_types=1);
use native_types;
function main(): void {
// Write to the file
$fp = fopen("data.txt", "w+");
$fp->write("Line 1\n");
$fp->write("Line 2\n");
$fp->write("Line 3\n");
// Go back to the beginning and read
$fp->seek(0);
while (!$fp->eof()) {
$line = $fp->getLine();
if ($line !== false) {
echo $line->trim();
echo " (长度: " . $line->trim()->length() . ")\n";
}
}
$fp->close();
}
?>
Further Reading
- High-precision type tutorial:
docs/HIGH_PRECISION_TYPES.md - Type system specification:
docs/NATIVE_TYPES.md - Universal methods implementation:
src/Parser/UniversalMethodCall.php - Integration tests:
tests/compiler/string_method/— String universal methods teststests/compiler/array_method/— Array universal methods teststests/compiler/stream_method/— Stream universal methods teststests/compiler/bigint/— BigInt universal methods teststests/compiler/decimal/— Decimal universal methods tests