- 修改generators.phpt使用exit替代echo进行跳过提示 - 新增iterators.phpt测试文件实现Iterator和IteratorAggregate接口 - 添加Range类测试基于生成器的迭代器聚合 - 实现FilterIterator类测试过滤功能 - 新增match-expression.phpt测试PHP8+匹配表达式功能 - 测试基本匹配、多重条件、严格比较和嵌套匹配场景pull/1/head
parent
23f2fa48af
commit
8bf5c9c806
3 changed files with 315 additions and 1 deletions
@ -0,0 +1,193 @@ |
||||
--TEST-- |
||||
Iterable and Iterator - Custom iteration with Traversable |
||||
--SKIPIF-- |
||||
<?php |
||||
exit("skip: Generator syntax not supported in AOT"); |
||||
?> |
||||
--FILE-- |
||||
<?php |
||||
// Test implementing Iterator interface |
||||
class NumberIterator implements Iterator { |
||||
private int $start; |
||||
private int $end; |
||||
private int $current = 0; |
||||
|
||||
public function __construct(int $start, int $end) { |
||||
$this->start = $start; |
||||
$this->end = $end; |
||||
$this->current = $start; |
||||
} |
||||
|
||||
public function rewind(): void { |
||||
$this->current = $this->start; |
||||
} |
||||
|
||||
public function current(): int { |
||||
return $this->current; |
||||
} |
||||
|
||||
public function key(): int { |
||||
return $this->current - $this->start; |
||||
} |
||||
|
||||
public function next(): void { |
||||
$this->current++; |
||||
} |
||||
|
||||
public function valid(): bool { |
||||
return $this->current <= $this->end; |
||||
} |
||||
} |
||||
|
||||
// Test implementing IteratorAggregate interface |
||||
class NumberCollection implements IteratorAggregate { |
||||
private array $numbers; |
||||
|
||||
public function __construct(array $numbers) { |
||||
$this->numbers = $numbers; |
||||
} |
||||
|
||||
public function getIterator(): Traversable { |
||||
return new ArrayIterator($this->numbers); |
||||
} |
||||
} |
||||
|
||||
// Test a simple iterable range |
||||
class Range implements IteratorAggregate { |
||||
private int $start; |
||||
private int $end; |
||||
|
||||
public function __construct(int $start, int $end) { |
||||
$this->start = $start; |
||||
$this->end = $end; |
||||
} |
||||
|
||||
public function getIterator(): Traversable { |
||||
for ($i = $this->start; $i <= $this->end; $i++) { |
||||
yield $i; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Test filtering iterator |
||||
class FilterIterator implements Iterator { |
||||
private Iterator $iterator; |
||||
private mixed $filterValue; |
||||
|
||||
public function __construct(Iterator $iterator, mixed $filterValue) { |
||||
$this->iterator = $iterator; |
||||
$this->filterValue = $filterValue; |
||||
|
||||
// Rewind to first valid element |
||||
$this->iterator->rewind(); |
||||
$this->advanceToValid(); |
||||
} |
||||
|
||||
private function advanceToValid(): void { |
||||
while ($this->iterator->valid() && $this->iterator->current() < $this->filterValue) { |
||||
$this->iterator->next(); |
||||
} |
||||
} |
||||
|
||||
public function rewind(): void { |
||||
$this->iterator->rewind(); |
||||
$this->advanceToValid(); |
||||
} |
||||
|
||||
public function current(): mixed { |
||||
return $this->iterator->current(); |
||||
} |
||||
|
||||
public function key(): mixed { |
||||
return $this->iterator->key(); |
||||
} |
||||
|
||||
public function next(): void { |
||||
$this->iterator->next(); |
||||
$this->advanceToValid(); |
||||
} |
||||
|
||||
public function valid(): bool { |
||||
return $this->iterator->valid(); |
||||
} |
||||
} |
||||
|
||||
function main() { |
||||
// Test custom Iterator |
||||
echo "Custom Iterator:\n"; |
||||
$iterator = new NumberIterator(5, 10); |
||||
foreach ($iterator as $key => $value) { |
||||
echo "{$key}: {$value}\n"; |
||||
} |
||||
|
||||
// Test IteratorAggregate with ArrayIterator |
||||
echo "\nIteratorAggregate:\n"; |
||||
$collection = new NumberCollection([10, 20, 30, 40, 50]); |
||||
foreach ($collection as $index => $number) { |
||||
echo "{$index}: {$number}\n"; |
||||
} |
||||
|
||||
// Test Generator-based IteratorAggregate |
||||
echo "\nGenerator-based:\n"; |
||||
$range = new Range(1, 5); |
||||
foreach ($range as $num) { |
||||
echo "{$num}\n"; |
||||
} |
||||
|
||||
// Test FilterIterator |
||||
echo "\nFilterIterator:\n"; |
||||
$baseIterator = new NumberIterator(1, 10); |
||||
$filterIterator = new FilterIterator($baseIterator, 5); |
||||
foreach ($filterIterator as $value) { |
||||
echo "{$value}\n"; |
||||
} |
||||
|
||||
// Test multiple iterations |
||||
echo "\nMultiple iterations:\n"; |
||||
$reusable = new Range(1, 3); |
||||
foreach ($reusable as $num) { |
||||
echo "First: {$num}\n"; |
||||
} |
||||
foreach ($reusable as $num) { |
||||
echo "Second: {$num}\n"; |
||||
} |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
Custom Iterator: |
||||
0: 5 |
||||
1: 6 |
||||
2: 7 |
||||
3: 8 |
||||
4: 9 |
||||
5: 10 |
||||
|
||||
IteratorAggregate: |
||||
0: 10 |
||||
1: 20 |
||||
2: 30 |
||||
3: 40 |
||||
4: 50 |
||||
|
||||
Generator-based: |
||||
1 |
||||
2 |
||||
3 |
||||
4 |
||||
5 |
||||
|
||||
FilterIterator: |
||||
5 |
||||
6 |
||||
7 |
||||
8 |
||||
9 |
||||
10 |
||||
|
||||
Multiple iterations: |
||||
First: 1 |
||||
First: 2 |
||||
First: 3 |
||||
Second: 1 |
||||
Second: 2 |
||||
Second: 3 |
||||
@ -0,0 +1,121 @@ |
||||
--TEST-- |
||||
Match Expression - PHP 8+ enhanced switch statement |
||||
--FILE-- |
||||
<?php |
||||
function test_basic_match($value) { |
||||
return match($value) { |
||||
1 => 'one', |
||||
2 => 'two', |
||||
3 => 'three', |
||||
default => 'other', |
||||
}; |
||||
} |
||||
|
||||
function test_multiple_conditions($status) { |
||||
return match($status) { |
||||
200, 201, 202 => 'success', |
||||
400, 401, 403, 404 => 'client_error', |
||||
500, 501, 502, 503 => 'server_error', |
||||
default => 'unknown', |
||||
}; |
||||
} |
||||
|
||||
function test_strict_comparison($value) { |
||||
return match($value) { |
||||
0 => 'integer zero', |
||||
'0' => 'string zero', |
||||
false => 'boolean false', |
||||
null => 'null value', |
||||
default => 'other', |
||||
}; |
||||
} |
||||
|
||||
function test_expression_result($a, $b, $op) { |
||||
return match($op) { |
||||
'add' => $a + $b, |
||||
'sub' => $a - $b, |
||||
'mul' => $a * $b, |
||||
'div' => $b !== 0 ? $a / $b : 'error', |
||||
default => 'invalid operation', |
||||
}; |
||||
} |
||||
|
||||
function test_nested_match($level) { |
||||
return match($level) { |
||||
1 => match(true) { |
||||
true => 'level 1 - true', |
||||
false => 'level 1 - false', |
||||
}, |
||||
2 => 'level 2', |
||||
default => 'other level', |
||||
}; |
||||
} |
||||
|
||||
function test_no_default($value) { |
||||
try { |
||||
return match($value) { |
||||
1 => 'one', |
||||
2 => 'two', |
||||
}; |
||||
} catch (UnhandledMatchError $e) { |
||||
return "Error: " . $e->getMessage(); |
||||
} |
||||
} |
||||
|
||||
function main() { |
||||
// Test basic match |
||||
var_dump(test_basic_match(1)); |
||||
var_dump(test_basic_match(2)); |
||||
var_dump(test_basic_match(5)); |
||||
|
||||
// Test multiple conditions |
||||
var_dump(test_multiple_conditions(200)); |
||||
var_dump(test_multiple_conditions(404)); |
||||
var_dump(test_multiple_conditions(500)); |
||||
var_dump(test_multiple_conditions(999)); |
||||
|
||||
// Test strict comparison |
||||
var_dump(test_strict_comparison(0)); |
||||
var_dump(test_strict_comparison('0')); |
||||
var_dump(test_strict_comparison(false)); |
||||
var_dump(test_strict_comparison(null)); |
||||
|
||||
// Test expression result |
||||
var_dump(test_expression_result(10, 5, 'add')); |
||||
var_dump(test_expression_result(10, 5, 'sub')); |
||||
var_dump(test_expression_result(10, 5, 'mul')); |
||||
var_dump(test_expression_result(10, 5, 'div')); |
||||
var_dump(test_expression_result(10, 0, 'div')); |
||||
|
||||
// Test nested match |
||||
var_dump(test_nested_match(1)); |
||||
var_dump(test_nested_match(2)); |
||||
var_dump(test_nested_match(3)); |
||||
|
||||
// Test no default (should throw error) |
||||
var_dump(test_no_default(1)); |
||||
var_dump(test_no_default(5)); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
string(3) "one" |
||||
string(3) "two" |
||||
string(5) "other" |
||||
string(7) "success" |
||||
string(12) "client_error" |
||||
string(12) "server_error" |
||||
string(7) "unknown" |
||||
string(12) "integer zero" |
||||
string(11) "string zero" |
||||
string(13) "boolean false" |
||||
string(10) "null value" |
||||
int(15) |
||||
int(5) |
||||
int(50) |
||||
int(2) |
||||
string(5) "error" |
||||
string(14) "level 1 - true" |
||||
string(7) "level 2" |
||||
string(11) "other level" |
||||
string(3) "one" |
||||
string(27) "Error: Unhandled match case" |
||||
Loading…
Reference in new issue