- 实现了函数调用、方法调用、静态调用和属性获取后的通用方法调用 - 新增 stream_cast 伪函数用于流类型转换测试 - 支持数组方法链式调用和可变操作 - 添加表达式上下文中的流转换功能 - 扩展了对内部函数反射返回类型的处理 - 优化了数组操作的返回值一致性 - 完善了通用方法调用的错误处理机制pull/1/head
parent
6309346c9a
commit
12d44084ec
6 changed files with 187 additions and 4 deletions
@ -0,0 +1,7 @@ |
|||||||
|
<?php |
||||||
|
function main() |
||||||
|
{ |
||||||
|
$arr = []; |
||||||
|
$arr->push(1); |
||||||
|
($arr->slice(0, 1))->push(2); |
||||||
|
} |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
<?php |
||||||
|
function main() |
||||||
|
{ |
||||||
|
$tmpfile = tempnam(sys_get_temp_dir(), 'aot'); |
||||||
|
$fp = fopen($tmpfile, 'w'); |
||||||
|
stream_cast()->write('data'); |
||||||
|
} |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
<?php |
||||||
|
function main() |
||||||
|
{ |
||||||
|
$tmpfile = tempnam(sys_get_temp_dir(), 'aot'); |
||||||
|
stream_cast(fopen($tmpfile, 'w'))->unknownMethod(); |
||||||
|
} |
||||||
@ -0,0 +1,49 @@ |
|||||||
|
--TEST-- |
||||||
|
stream_cast() pseudo-function for stream type casting |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function main() |
||||||
|
{ |
||||||
|
require __DIR__ . '/../../../src/Assert.php'; |
||||||
|
|
||||||
|
// Test 1: stream_cast identity — on an already-inferred stream variable |
||||||
|
$tmpfile = tempnam(sys_get_temp_dir(), 'aot'); |
||||||
|
$fp = fopen($tmpfile, 'w+'); |
||||||
|
$fp->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 |
||||||
@ -0,0 +1,114 @@ |
|||||||
|
--TEST-- |
||||||
|
Universal method call on expression results (FuncCall, MethodCall, StaticCall, PropertyFetch) |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
// --- Helpers: functions and classes --- |
||||||
|
|
||||||
|
function getString(): string |
||||||
|
{ |
||||||
|
return "hello world"; |
||||||
|
} |
||||||
|
|
||||||
|
function getInt(): int |
||||||
|
{ |
||||||
|
return 42; |
||||||
|
} |
||||||
|
|
||||||
|
function getFloat(): float |
||||||
|
{ |
||||||
|
return 3.14; |
||||||
|
} |
||||||
|
|
||||||
|
function getArray(): array |
||||||
|
{ |
||||||
|
return [1, 2, 3, 4, 5]; |
||||||
|
} |
||||||
|
|
||||||
|
class Helper { |
||||||
|
public string $name = "hello"; |
||||||
|
|
||||||
|
public function getName(): string |
||||||
|
{ |
||||||
|
return "test"; |
||||||
|
} |
||||||
|
|
||||||
|
public function getInt(): int |
||||||
|
{ |
||||||
|
return 100; |
||||||
|
} |
||||||
|
|
||||||
|
public static function staticName(): string |
||||||
|
{ |
||||||
|
return "STATIC"; |
||||||
|
} |
||||||
|
|
||||||
|
public static function staticArray(): array |
||||||
|
{ |
||||||
|
return ["a", "b", "c"]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main() |
||||||
|
{ |
||||||
|
require __DIR__ . '/../../src/Assert.php'; |
||||||
|
|
||||||
|
// --- Test 1: FuncCall -> 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 |
||||||
Loading…
Reference in new issue