- 在 ArgInfo 中新增 typeCheck、typeStr 和 typeNode 属性用于类型检查 - 在 FunctionDef 中新增 returnTypeCheck、returnTypeStr 和 returnTypeNode 属性 - 实现 buildTypeCheckFromNode 方法解析联合/可空类型节点 - 实现 genSingleTypeCondition 方法生成单个类型检查条件 - 实现 genUnionParamCheck 方法生成参数类型检查代码块 - 实现 genUnionReturnCheck 方法生成返回值类型检查代码块 - 在编译过程中集成参数和返回值的运行时类型检查 - 添加 union-param-check.phpt 和 union-return-check.phpt 测试用例 - 支持基本类型、类类型和特殊类型的联合类型检查 - 实现详细的错误消息生成机制pull/1/head
parent
593c6ec2a5
commit
3b5345d68e
6 changed files with 425 additions and 3 deletions
@ -0,0 +1,102 @@ |
|||||||
|
--TEST-- |
||||||
|
Union type: parameter runtime type checking |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function expect_int_or_string(int|string $x): void { |
||||||
|
var_dump($x); |
||||||
|
} |
||||||
|
|
||||||
|
function expect_int_or_string_or_null(int|string|null $x): void { |
||||||
|
var_dump($x); |
||||||
|
} |
||||||
|
|
||||||
|
function expect_int_or_float(int|float $x): void { |
||||||
|
var_dump($x); |
||||||
|
} |
||||||
|
|
||||||
|
function expect_nullable_int(?int $x): void { |
||||||
|
var_dump($x); |
||||||
|
} |
||||||
|
|
||||||
|
function expect_nullable_string(?string $x): void { |
||||||
|
var_dump($x); |
||||||
|
} |
||||||
|
|
||||||
|
function expect_bool_or_array(bool|array $x): void { |
||||||
|
var_dump($x); |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
// Valid calls - should pass |
||||||
|
expect_int_or_string(42); |
||||||
|
expect_int_or_string("hello"); |
||||||
|
expect_int_or_string_or_null(42); |
||||||
|
expect_int_or_string_or_null("hello"); |
||||||
|
expect_int_or_string_or_null(null); |
||||||
|
expect_int_or_float(42); |
||||||
|
expect_int_or_float(3.14); |
||||||
|
expect_nullable_int(42); |
||||||
|
expect_nullable_int(null); |
||||||
|
expect_nullable_string("test"); |
||||||
|
expect_nullable_string(null); |
||||||
|
expect_bool_or_array(true); |
||||||
|
expect_bool_or_array([1, 2, 3]); |
||||||
|
|
||||||
|
// Invalid calls - should throw TypeError |
||||||
|
$errors = []; |
||||||
|
|
||||||
|
try { |
||||||
|
expect_int_or_string(3.14); |
||||||
|
} catch (\TypeError $e) { |
||||||
|
$errors[] = $e->getMessage(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
expect_int_or_string([]); |
||||||
|
} catch (\TypeError $e) { |
||||||
|
$errors[] = $e->getMessage(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
expect_nullable_int("hello"); |
||||||
|
} catch (\TypeError $e) { |
||||||
|
$errors[] = $e->getMessage(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
expect_bool_or_array(42); |
||||||
|
} catch (\TypeError $e) { |
||||||
|
$errors[] = $e->getMessage(); |
||||||
|
} |
||||||
|
|
||||||
|
foreach ($errors as $err) { |
||||||
|
var_dump($err); |
||||||
|
} |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
int(42) |
||||||
|
string(5) "hello" |
||||||
|
int(42) |
||||||
|
string(5) "hello" |
||||||
|
NULL |
||||||
|
int(42) |
||||||
|
float(3.14) |
||||||
|
int(42) |
||||||
|
NULL |
||||||
|
string(4) "test" |
||||||
|
NULL |
||||||
|
bool(true) |
||||||
|
array(3) { |
||||||
|
[0]=> |
||||||
|
int(1) |
||||||
|
[1]=> |
||||||
|
int(2) |
||||||
|
[2]=> |
||||||
|
int(3) |
||||||
|
} |
||||||
|
string(80) "expect_int_or_string(): Argument #1 ($x) must be of type int|string, float given" |
||||||
|
string(80) "expect_int_or_string(): Argument #1 ($x) must be of type int|string, array given" |
||||||
|
string(74) "expect_nullable_int(): Argument #1 ($x) must be of type ?int, string given" |
||||||
|
string(78) "expect_bool_or_array(): Argument #1 ($x) must be of type bool|array, int given" |
||||||
@ -0,0 +1,69 @@ |
|||||||
|
--TEST-- |
||||||
|
Union type: return runtime type checking |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function return_int_or_string($value): int|string { |
||||||
|
return $value; |
||||||
|
} |
||||||
|
|
||||||
|
function return_nullable_int($value): ?int { |
||||||
|
return $value; |
||||||
|
} |
||||||
|
|
||||||
|
function return_int_or_float($value): int|float { |
||||||
|
return $value; |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
// Valid returns - should pass |
||||||
|
var_dump(return_int_or_string(42)); |
||||||
|
var_dump(return_int_or_string("hello")); |
||||||
|
var_dump(return_nullable_int(42)); |
||||||
|
var_dump(return_nullable_int(null)); |
||||||
|
var_dump(return_int_or_float(42)); |
||||||
|
var_dump(return_int_or_float(3.14)); |
||||||
|
|
||||||
|
// Invalid returns - should throw TypeError |
||||||
|
$errors = []; |
||||||
|
|
||||||
|
try { |
||||||
|
return_int_or_string(3.14); |
||||||
|
} catch (\TypeError $e) { |
||||||
|
$errors[] = $e->getMessage(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
return_int_or_string([]); |
||||||
|
} catch (\TypeError $e) { |
||||||
|
$errors[] = $e->getMessage(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
return_nullable_int("hello"); |
||||||
|
} catch (\TypeError $e) { |
||||||
|
$errors[] = $e->getMessage(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
return_int_or_float("hello"); |
||||||
|
} catch (\TypeError $e) { |
||||||
|
$errors[] = $e->getMessage(); |
||||||
|
} |
||||||
|
|
||||||
|
foreach ($errors as $err) { |
||||||
|
var_dump($err); |
||||||
|
} |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
int(42) |
||||||
|
string(5) "hello" |
||||||
|
int(42) |
||||||
|
NULL |
||||||
|
int(42) |
||||||
|
float(3.14) |
||||||
|
string(76) "return_int_or_string(): Return value must be of type int|string, float given" |
||||||
|
string(76) "return_int_or_string(): Return value must be of type int|string, array given" |
||||||
|
string(70) "return_nullable_int(): Return value must be of type ?int, string given" |
||||||
|
string(75) "return_int_or_float(): Return value must be of type int|float, string given" |
||||||
Loading…
Reference in new issue