- 添加可调用类型、数组类型、对象类型和可迭代类型的测试 - 添加标量类型声明包括整数、字符串、浮点数和布尔值的测试 - 添加空类型合并操作符 ?? 和 ??= 的语法测试 - 添加魔术方法包括 __clone、__serialize 和 __unserialize 的测试 - 在编译器基础类中增加对 callable 和 iterable 类型的支持pull/1/head
parent
646fb7d56d
commit
12696eeed4
6 changed files with 349 additions and 0 deletions
@ -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…
Reference in new issue