- 添加实例属性类型检查消息包含类名的测试用例 - 添加属性联合赋值操作使用运行时类型检查的测试用例 - 添加动态属性赋值TypeError捕获的测试用例 - 添加二元运算符操作数从左到右求值顺序的测试用例 - 添加原生优化调用参数从左到右求值的测试用例 - 添加构造函数属性提升联合参数检查的测试用例 fix(assign): 修复属性赋值时的类型检查问题 - 在属性赋值操作中添加对象属性类型检查包装 - 修复属性赋值表达式中的类型验证逻辑 - 添加静态属性赋值的类型检查支持 fix(ctor): 修复构造函数属性提升的参数验证顺序 - 将构造函数属性提升移到参数类型验证之后执行 - 在数组初始化计划后添加错误检查机制pull/5/head
parent
54bca6942e
commit
f8c37f91c3
11 changed files with 212 additions and 7 deletions
@ -0,0 +1,6 @@ |
||||
<?php |
||||
|
||||
function main(): void |
||||
{ |
||||
str_replace(search: "a", subject: "b"); |
||||
} |
||||
@ -0,0 +1,6 @@ |
||||
<?php |
||||
|
||||
function main(): void |
||||
{ |
||||
strlen(foo: "abc"); |
||||
} |
||||
@ -0,0 +1,10 @@ |
||||
<?php |
||||
|
||||
function target($a, $b): void |
||||
{ |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
target(a: 1, ...[2]); |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
--TEST-- |
||||
Constructor property promotion checks union parameter before assignment |
||||
--ENV-- |
||||
USE_ZEND_ALLOC=0 |
||||
--FILE-- |
||||
<?php |
||||
class PromotedUnionHolder |
||||
{ |
||||
public function __construct(public int|string $value) |
||||
{ |
||||
} |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
try { |
||||
new PromotedUnionHolder([]); |
||||
} catch (TypeError $e) { |
||||
var_dump($e->getMessage()); |
||||
} |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
string(96) "PromotedUnionHolder::__construct(): Argument #1 ($value) must be of type int|string, array given" |
||||
@ -0,0 +1,38 @@ |
||||
--TEST-- |
||||
Binary operator operands are evaluated left-to-right |
||||
--FILE-- |
||||
<?php |
||||
function main() |
||||
{ |
||||
var_dump((print "sub-left\n") - (print "sub-right\n")); |
||||
var_dump((print "nested-left\n") * ((print "nested-right-left\n") + (print "nested-right-right\n"))); |
||||
var_dump((print "eq-left\n") == (print "eq-right\n")); |
||||
var_dump((print "same-left\n") === (print "same-right\n")); |
||||
var_dump((print "spaceship-left\n") <=> (print "spaceship-right\n")); |
||||
var_dump((print "pow-left\n") ** (print "pow-right\n")); |
||||
var_dump(((print "logic-left\n") && false && (print "logic-right\n")) + (print "logic-after\n")); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
sub-left |
||||
sub-right |
||||
int(0) |
||||
nested-left |
||||
nested-right-left |
||||
nested-right-right |
||||
int(2) |
||||
eq-left |
||||
eq-right |
||||
bool(true) |
||||
same-left |
||||
same-right |
||||
bool(true) |
||||
spaceship-left |
||||
spaceship-right |
||||
int(0) |
||||
pow-left |
||||
pow-right |
||||
int(1) |
||||
logic-left |
||||
logic-after |
||||
int(1) |
||||
@ -0,0 +1,23 @@ |
||||
--TEST-- |
||||
Native optimized calls evaluate arguments left-to-right |
||||
--FILE-- |
||||
<?php |
||||
var_dump(str_repeat((print "repeat-left\n") ? "x" : "x", (print "repeat-right\n") + 1)); |
||||
var_dump(round((print "round-left\n") + 1.25, (print "round-right\n"))); |
||||
var_dump(strcmp((print "cmp-left\n") ? "a" : "a", (print "cmp-right\n") ? "b" : "b")); |
||||
$text = '<x>'; |
||||
var_dump($text->replace((print "method-left\n") ? "x" : "x", (print "method-right\n") ? "y" : "y")); |
||||
?> |
||||
--EXPECT-- |
||||
repeat-left |
||||
repeat-right |
||||
string(2) "xx" |
||||
round-left |
||||
round-right |
||||
float(2.3) |
||||
cmp-left |
||||
cmp-right |
||||
int(-1) |
||||
method-left |
||||
method-right |
||||
string(3) "<y>" |
||||
@ -0,0 +1,25 @@ |
||||
--TEST-- |
||||
type hits: instance property type check message includes class name |
||||
--FILE-- |
||||
<?php |
||||
class TypeHitPropertyMessage |
||||
{ |
||||
public int|string $union; |
||||
|
||||
public function setInvalid(): void |
||||
{ |
||||
try { |
||||
$this->union = null; |
||||
} catch (TypeError $e) { |
||||
var_dump($e->getMessage()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
(new TypeHitPropertyMessage())->setInvalid(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
string(69) "TypeHitPropertyMessage::$union must be of type int|string, null given" |
||||
@ -0,0 +1,32 @@ |
||||
--TEST-- |
||||
type hits: property coalesce assignment uses runtime type check |
||||
--ENV-- |
||||
USE_ZEND_ALLOC=0 |
||||
--FILE-- |
||||
<?php |
||||
class TypeHitCoalesceProperty |
||||
{ |
||||
public int|string $union; |
||||
|
||||
public function run(): void |
||||
{ |
||||
try { |
||||
$this->union ??= null; |
||||
} catch (TypeError $e) { |
||||
var_dump($e->getMessage()); |
||||
} |
||||
|
||||
$this->union = "ok"; |
||||
$this->union ??= null; |
||||
var_dump($this->union); |
||||
} |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
(new TypeHitCoalesceProperty())->run(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
string(70) "TypeHitCoalesceProperty::$union must be of type int|string, null given" |
||||
string(2) "ok" |
||||
@ -0,0 +1,30 @@ |
||||
--TEST-- |
||||
AOT dynamic property assignment TypeError can be caught |
||||
--FILE-- |
||||
<?php |
||||
class TypeHitDynamicProperty { |
||||
public int|string $union; |
||||
} |
||||
|
||||
function assign_dynamic(TypeHitDynamicProperty $obj, string $prop, mixed $value): void { |
||||
try { |
||||
$obj->$prop = $value; |
||||
var_dump('not reached'); |
||||
} catch (TypeError $e) { |
||||
var_dump(get_class($e)); |
||||
var_dump(str_contains($e->getMessage(), 'Cannot assign null to property TypeHitDynamicProperty::$union')); |
||||
} |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
$obj = new TypeHitDynamicProperty(); |
||||
assign_dynamic($obj, 'union', null); |
||||
$obj->union = 'ok'; |
||||
var_dump($obj->union); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
string(9) "TypeError" |
||||
bool(true) |
||||
string(2) "ok" |
||||
Loading…
Reference in new issue