diff --git a/docs/UNSUPPORTED_SYNTAX.md b/docs/UNSUPPORTED_SYNTAX.md index df5d84f9..4de5df5e 100644 --- a/docs/UNSUPPORTED_SYNTAX.md +++ b/docs/UNSUPPORTED_SYNTAX.md @@ -2203,6 +2203,64 @@ $firstChar = safeCharAccess($str, 0); --- +### 12. eval() 中的变量作用域限制 + +**状态**: 部分支持 +**PHP 版本**: 所有版本 +**描述**: AOT 编译器支持 `eval()` 语言结构,但 eval 内执行的 PHP 代码无法访问编译后函数的局部变量,只能通过 `$GLOBALS` 或 `return` 语句与编译代码交互。 + +**示例代码**: +``` +>=, &=, |=, ^= +--FILE-- +>= 2; + var_dump($c); + + // Bitwise AND assignment + $d = 0xFF; + $d &= 0x0F; + var_dump($d); + + // Bitwise OR assignment + $e = 0xF0; + $e |= 0x0F; + var_dump($e); + + // Bitwise XOR assignment + $f = 0xFF; + $f ^= 0x0F; + var_dump($f); + + // Combined + $x = 100; + $x %= 7; + $x += 10; + var_dump($x); + + echo "done\n"; +} + +?> +--EXPECT-- +int(2) +int(8) +int(4) +int(15) +int(255) +int(240) +int(12) +done diff --git a/tests/aot/break-continue-level.phpt b/tests/aot/break-continue-level.phpt new file mode 100644 index 00000000..da27c110 --- /dev/null +++ b/tests/aot/break-continue-level.phpt @@ -0,0 +1,20 @@ +--TEST-- +Break and continue with numeric levels +--SKIPIF-- + 1 not supported in AOT"; +?> +--FILE-- + +--EXPECT-- +done diff --git a/tests/aot/casts.phpt b/tests/aot/casts.phpt new file mode 100644 index 00000000..2f14c6c9 --- /dev/null +++ b/tests/aot/casts.phpt @@ -0,0 +1,55 @@ +--TEST-- +Type casts: (int), (float), (string), (bool) +--FILE-- + +--EXPECT-- +int(123) +int(3) +float(3.14) +float(10) +bool(true) +bool(false) +bool(true) +bool(false) +string(3) "123" +string(1) "1" +string(0) "" +bool(true) +bool(false) +int(5) +done diff --git a/tests/aot/error-suppress.phpt b/tests/aot/error-suppress.phpt new file mode 100644 index 00000000..1ac0d81d --- /dev/null +++ b/tests/aot/error-suppress.phpt @@ -0,0 +1,21 @@ +--TEST-- +Error suppression operator @ +--FILE-- + 1]; + $ret = @$arr["missing"]; + var_dump($ret); + + $result = @file_get_contents("/nonexistent/file/path"); + var_dump($result); + + echo "done\n"; +} + +?> +--EXPECT-- +NULL +bool(false) +done diff --git a/tests/aot/foreach-complex.phpt b/tests/aot/foreach-complex.phpt new file mode 100644 index 00000000..7caae230 --- /dev/null +++ b/tests/aot/foreach-complex.phpt @@ -0,0 +1,58 @@ +--TEST-- +foreach with key-value and nested structures +--FILE-- + 1, "b" => 2, "c" => 3]; + $keys = []; + $vals = []; + foreach ($arr as $k => $v) { + $keys[] = $k; + $vals[] = $v; + } + var_dump($keys); + var_dump($vals); + + // Nested foreach + $matrix = [[1, 2], [3, 4]]; + $sum = 0; + foreach ($matrix as $row) { + foreach ($row as $val) { + $sum += $val; + } + } + var_dump($sum); + + // Foreach on array literal + $count = 0; + foreach ([10, 20, 30] as $item) { + $count += $item; + } + var_dump($count); + + echo "done\n"; +} + +?> +--EXPECT-- +array(3) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" + [2]=> + string(1) "c" +} +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +int(10) +int(60) +done diff --git a/tests/aot/goto.phpt b/tests/aot/goto.phpt new file mode 100644 index 00000000..2172f578 --- /dev/null +++ b/tests/aot/goto.phpt @@ -0,0 +1,42 @@ +--TEST-- +Goto and label statements +--FILE-- + +--EXPECT-- +int(21) diff --git a/tests/aot/heredoc-nowdoc.phpt b/tests/aot/heredoc-nowdoc.phpt new file mode 100644 index 00000000..75b94c60 --- /dev/null +++ b/tests/aot/heredoc-nowdoc.phpt @@ -0,0 +1,31 @@ +--TEST-- +Heredoc and nowdoc string syntax +--FILE-- + +--EXPECT-- +string(39) "Hello, World! +This is a heredoc string." +string(40) "Hello, $name! +This does NOT interpolate." +done diff --git a/tests/aot/instanceof-test.phpt b/tests/aot/instanceof-test.phpt new file mode 100644 index 00000000..bb0431f0 --- /dev/null +++ b/tests/aot/instanceof-test.phpt @@ -0,0 +1,34 @@ +--TEST-- +instanceof operator +--FILE-- + +--EXPECT-- +bool(true) +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) +done diff --git a/tests/aot/isset-complex.phpt b/tests/aot/isset-complex.phpt new file mode 100644 index 00000000..82e1d706 --- /dev/null +++ b/tests/aot/isset-complex.phpt @@ -0,0 +1,48 @@ +--TEST-- +isset with multiple arguments and edge cases +--FILE-- + 1, "y" => null]; + var_dump(isset($arr["x"])); + var_dump(isset($arr["y"])); + var_dump(isset($arr["z"])); + + // Nested isset + $data = ["user" => ["name" => "Alice"]]; + var_dump(isset($data["user"]["name"])); + var_dump(isset($data["user"]["email"])); + var_dump(isset($data["missing"]["key"])); + + echo "done\n"; +} + +?> +--EXPECT-- +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(true) +bool(false) +bool(false) +bool(true) +bool(false) +bool(false) +done diff --git a/tests/aot/object-cast.phpt b/tests/aot/object-cast.phpt new file mode 100644 index 00000000..8e1365b5 --- /dev/null +++ b/tests/aot/object-cast.phpt @@ -0,0 +1,23 @@ +--TEST-- +Object cast (object) from array +--FILE-- + "test", "value" => 42]; + var_dump($data->name); + var_dump($data->value); + + $empty = (object) []; + var_dump((array) $empty); + + echo "done\n"; +} + +?> +--EXPECT-- +string(4) "test" +int(42) +array(0) { +} +done diff --git a/tests/aot/ternary-shorthand.phpt b/tests/aot/ternary-shorthand.phpt new file mode 100644 index 00000000..fdb597f5 --- /dev/null +++ b/tests/aot/ternary-shorthand.phpt @@ -0,0 +1,58 @@ +--TEST-- +Ternary shorthand operator ?: +--FILE-- + "present"]; + $result6 = $arr["missing"] ?: "not found"; + var_dump($result6); + + $result7 = $arr["key"] ?: "not found"; + var_dump($result7); + + // Nested ternary shorthand + $x = ""; + $y = "hello"; + $result8 = $x ?: ($y ?: "neither"); + var_dump($result8); + + echo "done\n"; +} + +?> +--EXPECT-- +string(5) "hello" +string(5) "empty" +int(42) +string(8) "fallback" +string(5) "final" +string(9) "not found" +string(7) "present" +string(5) "hello" +done diff --git a/tests/aot/unset.phpt b/tests/aot/unset.phpt new file mode 100644 index 00000000..4aa330ec --- /dev/null +++ b/tests/aot/unset.phpt @@ -0,0 +1,45 @@ +--TEST-- +unset on arrays and variables +--FILE-- + 1, "y" => 2, "z" => 3]; + unset($arr["y"]); + var_dump(count($arr)); + var_dump(isset($arr["y"])); + var_dump($arr["x"]); + var_dump($arr["z"]); + + // Unset last element + $arr2 = [1, 2, 3, 4]; + unset($arr2[3]); + var_dump(count($arr2)); + + // Unset with variable key + $items = ["a" => 1, "b" => 2, "c" => 3]; + $key = "b"; + unset($items[$key]); + var_dump(count($items)); + var_dump(isset($items["b"])); + + echo "done\n"; +} + +?> +--EXPECT-- +bool(false) +int(2) +bool(false) +int(1) +int(3) +int(3) +int(2) +bool(false) +done