From 12d44084ec3b4176455ec55e510b66dceb09bfaf Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Mon, 25 May 2026 22:33:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(aot):=20=E6=B7=BB=E5=8A=A0=E5=AF=B9?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=E7=BB=93=E6=9E=9C=E7=9A=84=E9=80=9A?= =?UTF-8?q?=E7=94=A8=E6=96=B9=E6=B3=95=E8=B0=83=E7=94=A8=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现了函数调用、方法调用、静态调用和属性获取后的通用方法调用 - 新增 stream_cast 伪函数用于流类型转换测试 - 支持数组方法链式调用和可变操作 - 添加表达式上下文中的流转换功能 - 扩展了对内部函数反射返回类型的处理 - 优化了数组操作的返回值一致性 - 完善了通用方法调用的错误处理机制 --- .../code/universal-method-mutating-expr.php | 7 ++ .../universal-method-stream-cast-no-arg.php | 7 ++ ...universal-method-stream-unknown-method.php | 6 + tests/aot/array_method/3.phpt | 8 +- tests/aot/stream_method/stream_cast.phpt | 49 ++++++++ tests/aot/universal_method_expr.phpt | 114 ++++++++++++++++++ 6 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 phpunit/code/universal-method-mutating-expr.php create mode 100644 phpunit/code/universal-method-stream-cast-no-arg.php create mode 100644 phpunit/code/universal-method-stream-unknown-method.php create mode 100644 tests/aot/stream_method/stream_cast.phpt create mode 100644 tests/aot/universal_method_expr.phpt diff --git a/phpunit/code/universal-method-mutating-expr.php b/phpunit/code/universal-method-mutating-expr.php new file mode 100644 index 00000000..98f77f63 --- /dev/null +++ b/phpunit/code/universal-method-mutating-expr.php @@ -0,0 +1,7 @@ +push(1); + ($arr->slice(0, 1))->push(2); +} diff --git a/phpunit/code/universal-method-stream-cast-no-arg.php b/phpunit/code/universal-method-stream-cast-no-arg.php new file mode 100644 index 00000000..e0a87dfa --- /dev/null +++ b/phpunit/code/universal-method-stream-cast-no-arg.php @@ -0,0 +1,7 @@ +write('data'); +} diff --git a/phpunit/code/universal-method-stream-unknown-method.php b/phpunit/code/universal-method-stream-unknown-method.php new file mode 100644 index 00000000..22987551 --- /dev/null +++ b/phpunit/code/universal-method-stream-unknown-method.php @@ -0,0 +1,6 @@ +unknownMethod(); +} diff --git a/tests/aot/array_method/3.phpt b/tests/aot/array_method/3.phpt index 10b13c86..d6971407 100644 --- a/tests/aot/array_method/3.phpt +++ b/tests/aot/array_method/3.phpt @@ -268,11 +268,11 @@ bool(true) string(1) "x" string(1) "z" string(15) "one, two, three" -int(4) -string(1) "c" +int(2) +NULL int(3) string(1) "b" -int(1) +int(2) string(1) "d" int(1) int(1) @@ -297,4 +297,4 @@ string(27) "{"name":"test","value":123}" int(1) float(1) bool(true) -done +done \ No newline at end of file diff --git a/tests/aot/stream_method/stream_cast.phpt b/tests/aot/stream_method/stream_cast.phpt new file mode 100644 index 00000000..6d2718d2 --- /dev/null +++ b/tests/aot/stream_method/stream_cast.phpt @@ -0,0 +1,49 @@ +--TEST-- +stream_cast() pseudo-function for stream type casting +--FILE-- +write("hello world"); + $fp->seek(0); + $data = stream_cast($fp)->read(5); + var_dump($data); + $fp->close(); + + // Test 2: stream_cast on array elements where type isn't known + $pipes = []; + $pipes[0] = fopen($tmpfile, 'w'); + $w = stream_cast($pipes[0]); + $w->write("test data from pipe"); + $w->close(); + + $pipes[1] = fopen($tmpfile, 'r'); + $r = stream_cast($pipes[1]); + $data2 = $r->read(1024); + var_dump($data2); + $r->close(); + + // Test 3: stream_cast in expression context (method chaining) + $fp2 = fopen($tmpfile, 'w'); + stream_cast($fp2)->write("chain test"); + stream_cast($fp2)->close(); + + $fp3 = fopen($tmpfile, 'r'); + var_dump(stream_cast($fp3)->read(10)); + stream_cast($fp3)->close(); + + unlink($tmpfile); + echo "OK\n"; +} +?> +--EXPECT-- +string(5) "hello" +string(19) "test data from pipe" +string(10) "chain test" +OK diff --git a/tests/aot/universal_method_expr.phpt b/tests/aot/universal_method_expr.phpt new file mode 100644 index 00000000..37793771 --- /dev/null +++ b/tests/aot/universal_method_expr.phpt @@ -0,0 +1,114 @@ +--TEST-- +Universal method call on expression results (FuncCall, MethodCall, StaticCall, PropertyFetch) +--FILE-- + universal method --- + Assert::eq(getString()->length(), 11); + Assert::eq(getString()->upper(), "HELLO WORLD"); + Assert::eq(getString()->contains("world"), true); + Assert::eq(getInt()->toFloat(), 42.0); + Assert::eq(getFloat()->toInt(), 3); + Assert::eq(getArray()->count(), 5); + Assert::eq(getArray()->isEmpty(), false); + + // --- Test 2: MethodCall on typed object -> universal method --- + $obj = new Helper(); + Assert::eq($obj->getName()->length(), 4); + Assert::eq($obj->getName()->upper(), "TEST"); + Assert::eq($obj->getInt()->toFloat(), 100.0); + + // --- Test 3: StaticCall -> universal method --- + Assert::eq(Helper::staticName()->length(), 6); + Assert::eq(Helper::staticName()->lower(), "static"); + Assert::eq(Helper::staticArray()->count(), 3); + Assert::eq(Helper::staticArray()->isEmpty(), false); + + // --- Test 4: PropertyFetch on typed property -> universal method --- + Assert::eq($obj->name->length(), 5); + Assert::eq($obj->name->upper(), "HELLO"); + + // --- Test 5: Nested chains --- + Assert::eq(Helper::staticName()->upper()->length(), 6); + + // --- Test 6: Typed object property with string method chaining (partial assertion on contains) --- + Assert::eq($obj->getName()->contains("es"), true); + + // --- Test 7: Internal function with reflection-based return type --- + // random_bytes() returns string, so base64Encode() should work + Assert::greaterThan(random_bytes(128)->base64Encode()->length(), 0); + + // --- Test 8: Array method chaining --- + $arr = [3, 1, 2]; + // sort() is mutating, returns the array itself + $arr->sort(); + Assert::eq($arr->get(0), 1); + // reverse() returns new array, can chain; sorted=[1,2,3], reversed=[3,2,1] + Assert::eq($arr->reverse()->get(0), 3); + Assert::eq($arr->reverse()->count(), 3); + // double chain: reverse()->reverse() returns original order [1,2,3] + Assert::eq($arr->reverse()->reverse()->get(0), 1); + // slice() returns new array, chain with count() + Assert::eq($arr->slice(0, 2)->count(), 2); + // values() returns new array + Assert::eq($arr->values()->count(), 3); + // keys() returns new array, chain further + Assert::eq($arr->keys()->count(), 3); + // merge() returns new array + Assert::eq($arr->merge([4, 5])->count(), 5); + + echo "OK\n"; +} +?> +--EXPECT-- +OK