- 添加可调用类型、数组类型、对象类型和可迭代类型的测试 - 添加标量类型声明包括整数、字符串、浮点数和布尔值的测试 - 添加空类型合并操作符 ?? 和 ??= 的语法测试 - 添加魔术方法包括 __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