test(type): 添加类型声明相关测试用例

- 添加可调用类型、数组类型、对象类型和可迭代类型的测试
- 添加标量类型声明包括整数、字符串、浮点数和布尔值的测试
- 添加空类型合并操作符 ?? 和 ??= 的语法测试
- 添加魔术方法包括 __clone、__serialize 和 __unserialize 的测试
- 在编译器基础类中增加对 callable 和 iterable 类型的支持
pull/1/head
韩天峰 5 months ago
parent 646fb7d56d
commit 12696eeed4
  1. 5
      src/Php/CompilerBase.php
  2. 69
      tests/aot/magic_methods/misc.phpt
  3. 128
      tests/aot/null-coalescing.phpt
  4. 52
      tests/aot/type_decl/001.phpt
  5. 64
      tests/aot/type_decl/002.phpt
  6. 31
      tests/aot/type_decl/003.phpt

@ -1778,6 +1778,11 @@ class CompilerBase extends \PhpAot\Core\Translator
case 'void':
$this->fatalError($param, 'Cannot use `void` as a parameter type.');
// no break
// callable 类型,可以是字符串、数组、对象
// 1) 'foo' 函数名称字符串, 2) [ $obj, 'bar' ] 对象方法数组, 3) Closure 对象, 4) [ 'class', 'staticMethod'] 类名+静态方法数组
case 'callable':
// iterable 类型,可以是数组或者对象
case 'iterable':
case 'mixed':
return self::TYPE_VAR;
case 'self':

@ -0,0 +1,69 @@
--TEST--
Magic Methods - __get, __set, __call, __invoke etc.
--FILE--
<?php
class Point {
public function __construct(
private float $x = 0.0,
private float $y = 0.0
) {}
// __clone
public function __clone() {
$this->x *= 2;
$this->y *= 2;
}
public function getX(): float {
return $this->x;
}
public function getY(): float {
return $this->y;
}
}
class SerializableClass {
public function __construct(
public string $name,
public int $value
) {}
// __serialize and __unserialize (PHP 7.4+)
public function __serialize(): array {
return [
'name' => strtoupper($this->name),
'value' => $this->value * 2,
];
}
public function __unserialize(array $data): void {
$this->name = strtolower($data['name']);
$this->value = $data['value'] / 2;
}
}
function main() {
// Test __clone
$point1 = new Point(5.0, 10.0);
$point2 = clone $point1;
var_dump($point1->getX());
var_dump($point2->getX());
var_dump($point1->getY());
var_dump($point2->getY());
// Test __serialize and __unserialize
$obj = new SerializableClass('Test', 100);
$serialized = serialize($obj);
$unserialized = unserialize($serialized);
var_dump($unserialized->name);
var_dump($unserialized->value);
}
?>
--EXPECT--
float(5)
float(10)
float(10)
float(20)
string(4) "test"
int(100)

@ -0,0 +1,128 @@
--TEST--
Null Coalescing Operators - ?? and ??= syntax
--FILE--
<?php
// Test basic null coalescing operator (??)
function test_basic_coalesce($value) {
return $value ?? 'default';
}
// Test chained null coalescing
function test_chained_coalesce($a, $b, $c) {
return $a ?? $b ?? $c ?? 'all null';
}
// Test null coalescing assignment (??=)
class Config {
private array $settings = [];
public function setDefault(string $key, mixed $default): void {
$this->settings[$key] ??= $default;
}
public function get(string $key): mixed {
return $this->settings[$key] ?? null;
}
public function getAll(): array {
return $this->settings;
}
}
// Test with array access
function test_array_coalesce(array $data, string $key) {
return $data[$key] ?? 'not set';
}
// Test with nested arrays
function test_nested_coalesce(array $data) {
return $data['user']['profile']['name'] ?? 'Anonymous';
}
// Test in expressions
function test_expression($value) {
$result = ($value ?? 0) * 2;
return $result;
}
function main() {
// Test basic coalescing
var_dump(test_basic_coalesce(null));
var_dump(test_basic_coalesce('exists'));
var_dump(test_basic_coalesce(0));
var_dump(test_basic_coalesce(false));
var_dump(test_basic_coalesce(''));
// Test chained coalescing
var_dump(test_chained_coalesce(null, null, 'third'));
var_dump(test_chained_coalesce(null, 'second', 'third'));
var_dump(test_chained_coalesce('first', 'second', 'third'));
var_dump(test_chained_coalesce(null, null, null));
// Test null coalescing assignment
$config = new Config();
$config->setDefault('debug', false);
$config->setDefault('timeout', 30);
$config->setDefault('debug', true); // Should not override
var_dump($config->getAll());
// Test array coalescing
$arr1 = ['name' => 'John'];
$arr2 = [];
var_dump(test_array_coalesce($arr1, 'name'));
var_dump(test_array_coalesce($arr1, 'age'));
var_dump(test_array_coalesce($arr2, 'name'));
// Test nested coalescing
$data1 = ['user' => ['profile' => ['name' => 'Alice']]];
$data2 = ['user' => []];
$data3 = [];
var_dump(test_nested_coalesce($data1));
var_dump(test_nested_coalesce($data2));
var_dump(test_nested_coalesce($data3));
// Test in expressions
var_dump(test_expression(null));
var_dump(test_expression(5));
var_dump(test_expression(0));
// Test complex scenario
$options = [
'limit' => null,
'offset' => 10,
];
$limit = $options['limit'] ?? 100;
$offset = $options['offset'] ?? 0;
var_dump($limit);
var_dump($offset);
}
?>
--EXPECT--
string(7) "default"
string(6) "exists"
int(0)
bool(false)
string(0) ""
string(5) "third"
string(6) "second"
string(5) "first"
string(8) "all null"
array(2) {
["debug"]=>
bool(false)
["timeout"]=>
int(30)
}
string(4) "John"
string(7) "not set"
string(7) "not set"
string(5) "Alice"
string(9) "Anonymous"
string(9) "Anonymous"
int(0)
int(10)
int(0)
int(100)
int(10)

@ -0,0 +1,52 @@
--TEST--
Type Declarations - Strict and weak typing modes
--FILE--
<?php
declare(strict_types=1);
// Test callable type
function apply_callable(callable $callback, int $value): int {
return $callback($value);
}
// Test array type
function process_array(array $data): int {
return count($data);
}
// Test object type
function get_class_name(object $obj): string {
return get_class($obj);
}
// Test iterable type
function sum_iterable(iterable $numbers): int {
$sum = 0;
foreach ($numbers as $num) {
$sum += $num;
}
return $sum;
}
class TestClass {}
function main() {
// Test callable type
var_dump(apply_callable(fn($x) => $x * 2, 5));
var_dump(apply_callable('abs', -10));
// Test array type
var_dump(process_array([1, 2, 3]));
var_dump(process_array([]));
// Test object type
$testObj = new TestClass();
var_dump(get_class_name($testObj));
}
?>
--EXPECT--
int(10)
int(10)
int(3)
int(0)
string(9) "TestClass"

@ -0,0 +1,64 @@
--TEST--
Type Declarations - Strict and weak typing modes
--FILE--
<?php
declare(strict_types=1);
// Test scalar type declarations
function add_integers(int $a, int $b): int {
return $a + $b;
}
function concatenate(string $a, string $b): string {
return $a . $b;
}
function multiply_floats(float $a, float $b): float {
return $a * $b;
}
function negate(bool $value): bool {
return !$value;
}
// Test nullable types
function greet(?string $name): ?string {
if ($name === null) {
return null;
}
return "Hello, " . $name;
}
function main() {
// Test integer types
var_dump(add_integers(5, 10));
var_dump(add_integers(-3, 7));
// Test string types
var_dump(concatenate("Hello, ", "World!"));
var_dump(concatenate("", "Empty"));
// Test float types
var_dump(multiply_floats(2.5, 4.0));
var_dump(multiply_floats(0.1, 0.2));
// Test boolean types
var_dump(negate(true));
var_dump(negate(false));
// Test nullable types
var_dump(greet("Alice"));
var_dump(greet(null));
}
?>
--EXPECT--
int(15)
int(4)
string(13) "Hello, World!"
string(5) "Empty"
float(10)
float(0.020000000000000004)
bool(false)
bool(true)
string(12) "Hello, Alice"
NULL

@ -0,0 +1,31 @@
--TEST--
Type Declarations - Strict and weak typing modes
--FILE--
<?php
declare(strict_types=1);
// Test iterable type
function sum_iterable(iterable $numbers): int {
$sum = 0;
foreach ($numbers as $num) {
$sum += $num;
}
return $sum;
}
function main() {
// Test iterable type
var_dump(sum_iterable([1, 2, 3, 4, 5]));
// Test with strict types enabled (should throw TypeError for wrong types)
try {
// This would fail in strict mode: add_integers("5", "10");
echo "Strict mode enabled\n";
} catch (TypeError $e) {
echo "TypeError: " . $e->getMessage() . "\n";
}
}
?>
--EXPECT--
int(15)
Strict mode enabled
Loading…
Cancel
Save