- 移除测试文件中不必要的 use native_types 语句 - 新增 call-interface-method.phpt 测试接口方法调用功能 - 新增 call-magic-fallback-typed-object.phpt 测试魔法方法回调功能 - 新增 call-multilevel-override.phpt 测试多层级继承方法重写功能 - 新增 call-parent-sibling-dispatch.phpt 测试父类参数分发到兄弟类方法功能 - 新增 call-protected-override.phpt 测试受保护方法重写功能 - 添加命名空间重写键名使用完整类名的单元测试 - 添加 static 属性 array_pop 操作的调试测试用例pull/3/head
parent
a7b5b248fb
commit
23f1a1eef9
10 changed files with 271 additions and 6 deletions
@ -0,0 +1,60 @@ |
||||
<?php |
||||
class StackHolder |
||||
{ |
||||
public static array $stack = []; |
||||
|
||||
public static function push(string $item): void |
||||
{ |
||||
self::$stack[] = $item; |
||||
} |
||||
|
||||
public static function pop(): void |
||||
{ |
||||
// 触发 bug: AOT 对 static 属性 array_pop 生成 php::toReference(v) 缺第 2 参数 |
||||
array_pop(self::$stack); |
||||
} |
||||
|
||||
public static function count(): int |
||||
{ |
||||
return count(self::$stack); |
||||
} |
||||
} |
||||
|
||||
// ── 对照:array_pop($localVar) 走不同代码生成路径,应该正常 ── |
||||
function local_pop_test(): string |
||||
{ |
||||
$arr = ['x', 'y', 'z']; |
||||
array_pop($arr); |
||||
|
||||
if (count($arr) !== 2) { |
||||
return 'FAIL: local_pop_test expected 2, got ' . count($arr); |
||||
} |
||||
if ($arr[0] !== 'x' || $arr[1] !== 'y') { |
||||
return 'FAIL: local_pop_test wrong elements'; |
||||
} |
||||
|
||||
return 'OK'; |
||||
} |
||||
|
||||
function main(): int |
||||
{ |
||||
// 测试 static 属性(已知 bug,预期编译失败) |
||||
StackHolder::push('a'); |
||||
StackHolder::push('b'); |
||||
StackHolder::pop(); |
||||
|
||||
if (StackHolder::count() !== 1) { |
||||
echo "FAIL: static_pop expected 1, got " . StackHolder::count() . "\n"; |
||||
return 1; |
||||
} |
||||
|
||||
// 测试局部变量(应该正常) |
||||
$result = local_pop_test(); |
||||
echo $result . "\n"; |
||||
if ($result !== 'OK') { |
||||
return 1; |
||||
} |
||||
|
||||
echo "ALL OK\n"; |
||||
return 0; |
||||
} |
||||
@ -0,0 +1,32 @@ |
||||
--TEST-- |
||||
call interface method through concrete object |
||||
--FILE-- |
||||
<?php |
||||
interface Runner |
||||
{ |
||||
public function run(): string; |
||||
} |
||||
|
||||
class FastRunner implements Runner |
||||
{ |
||||
public function run(): string |
||||
{ |
||||
return 'fast'; |
||||
} |
||||
} |
||||
|
||||
function invoke(Runner $runner): string |
||||
{ |
||||
$alias = $runner; |
||||
return $alias->run(); |
||||
} |
||||
|
||||
function main(): int |
||||
{ |
||||
$r = invoke(new FastRunner()); |
||||
echo "result: $r\n"; |
||||
return $r === 'fast' ? 0 : 1; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
result: fast |
||||
@ -0,0 +1,29 @@ |
||||
--TEST-- |
||||
missing method on typed object dispatches to __call |
||||
--FILE-- |
||||
<?php |
||||
use native_types; |
||||
|
||||
class DynamicHandler |
||||
{ |
||||
public function __call(string $name, array $args): string |
||||
{ |
||||
return $name . ':' . implode(',', $args); |
||||
} |
||||
} |
||||
|
||||
function invoke(DynamicHandler $handler): string |
||||
{ |
||||
$alias = $handler; |
||||
return $alias->missing('a', 'b'); |
||||
} |
||||
|
||||
function main(): int |
||||
{ |
||||
$r = invoke(new DynamicHandler()); |
||||
echo "result: $r\n"; |
||||
return $r === 'missing:a,b' ? 0 : 1; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
result: missing:a,b |
||||
@ -0,0 +1,41 @@ |
||||
--TEST-- |
||||
call method overridden in grandchild through base parameter |
||||
--FILE-- |
||||
<?php |
||||
use native_types; |
||||
|
||||
class Base |
||||
{ |
||||
public function value(): string |
||||
{ |
||||
return 'base'; |
||||
} |
||||
} |
||||
|
||||
class Middle extends Base |
||||
{ |
||||
} |
||||
|
||||
class Leaf extends Middle |
||||
{ |
||||
public function value(): string |
||||
{ |
||||
return 'leaf'; |
||||
} |
||||
} |
||||
|
||||
function readValue(Base $obj): string |
||||
{ |
||||
$alias = $obj; |
||||
return $alias->value(); |
||||
} |
||||
|
||||
function main(): int |
||||
{ |
||||
$r = readValue(new Leaf()); |
||||
echo "result: $r\n"; |
||||
return $r === 'leaf' ? 0 : 1; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
result: leaf |
||||
@ -0,0 +1,48 @@ |
||||
--TEST-- |
||||
call overridden method on sibling subclasses through parent parameter |
||||
--FILE-- |
||||
<?php |
||||
use native_types; |
||||
|
||||
class Base |
||||
{ |
||||
public function name(): string |
||||
{ |
||||
return 'base'; |
||||
} |
||||
} |
||||
|
||||
class Left extends Base |
||||
{ |
||||
public function name(): string |
||||
{ |
||||
return 'left'; |
||||
} |
||||
} |
||||
|
||||
class Right extends Base |
||||
{ |
||||
public function name(): string |
||||
{ |
||||
return 'right'; |
||||
} |
||||
} |
||||
|
||||
function readName(Base $obj): string |
||||
{ |
||||
$alias = $obj; |
||||
return $alias->name(); |
||||
} |
||||
|
||||
function main(): int |
||||
{ |
||||
$left = readName(new Left()); |
||||
$right = readName(new Right()); |
||||
echo "left: $left\n"; |
||||
echo "right: $right\n"; |
||||
return $left === 'left' && $right === 'right' ? 0 : 1; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
left: left |
||||
right: right |
||||
@ -0,0 +1,41 @@ |
||||
--TEST-- |
||||
protected overridden method remains virtual through parent wrapper |
||||
--FILE-- |
||||
<?php |
||||
use native_types; |
||||
|
||||
class Base |
||||
{ |
||||
protected function token(): string |
||||
{ |
||||
return 'base'; |
||||
} |
||||
|
||||
public function expose(): string |
||||
{ |
||||
return $this->token(); |
||||
} |
||||
} |
||||
|
||||
class Child extends Base |
||||
{ |
||||
protected function token(): string |
||||
{ |
||||
return 'child'; |
||||
} |
||||
} |
||||
|
||||
function main(): int |
||||
{ |
||||
$base = new Base(); |
||||
$child = new Child(); |
||||
$a = $base->expose(); |
||||
$b = $child->expose(); |
||||
echo "base: $a\n"; |
||||
echo "child: $b\n"; |
||||
return $a === 'base' && $b === 'child' ? 0 : 1; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
base: base |
||||
child: child |
||||
Loading…
Reference in new issue