parent
c740a24501
commit
aab412084f
12 changed files with 326 additions and 0 deletions
@ -0,0 +1,14 @@ |
||||
--TEST-- |
||||
die with string should print message and terminate without fatal error |
||||
--ENV-- |
||||
USE_ZEND_ALLOC=0 |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() { |
||||
die("done\n"); |
||||
echo "unreachable\n"; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
done |
||||
@ -0,0 +1,35 @@ |
||||
--TEST-- |
||||
closure use by reference should work with nested control flow |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() { |
||||
$log = []; |
||||
$counter = 0; |
||||
|
||||
$push = function (string $label, int $value) use (&$log, &$counter): int { |
||||
$log[] = $label . ':' . $counter; |
||||
$counter++; |
||||
|
||||
return match ($value) { |
||||
1 => $value + $counter, |
||||
default => $counter, |
||||
}; |
||||
}; |
||||
|
||||
var_dump($push('a', 1)); |
||||
var_dump($push('b', 2)); |
||||
var_dump($log); |
||||
var_dump($counter); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(2) |
||||
int(2) |
||||
array(2) { |
||||
[0]=> |
||||
string(3) "a:0" |
||||
[1]=> |
||||
string(3) "b:1" |
||||
} |
||||
int(2) |
||||
@ -0,0 +1,29 @@ |
||||
--TEST-- |
||||
closure variadic parameter should work with unpacked positional arguments |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() { |
||||
$log = []; |
||||
$fn = function ($a, $b = 20, ...$rest) use (&$log) { |
||||
$log[] = $a + $b + array_sum($rest); |
||||
var_dump($a, $b, $rest); |
||||
}; |
||||
|
||||
$fn(...[10, 200, 300, 400]); |
||||
var_dump($log); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(10) |
||||
int(200) |
||||
array(2) { |
||||
[0]=> |
||||
int(300) |
||||
[1]=> |
||||
int(400) |
||||
} |
||||
array(1) { |
||||
[0]=> |
||||
int(910) |
||||
} |
||||
@ -0,0 +1,42 @@ |
||||
--TEST-- |
||||
composed ternary and match expressions should evaluate side effects once |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function side_effect(string $label, &$counter, $value) { |
||||
echo $label . ':' . $counter . "\n"; |
||||
$counter++; |
||||
return $value; |
||||
} |
||||
|
||||
function main() { |
||||
$n = 0; |
||||
|
||||
$ternary = side_effect('ternary-cond', $n, true) |
||||
? side_effect('ternary-if', $n, 'yes') |
||||
: side_effect('ternary-else', $n, 'no'); |
||||
|
||||
var_dump($ternary); |
||||
var_dump($n); |
||||
|
||||
$match = match (side_effect('match-subject', $n, 2)) { |
||||
side_effect('match-arm-1', $n, 1) => side_effect('match-body-1', $n, 'one'), |
||||
side_effect('match-arm-2', $n, 2) => side_effect('match-body-2', $n, 'two'), |
||||
default => side_effect('match-default', $n, 'default'), |
||||
}; |
||||
|
||||
var_dump($match); |
||||
var_dump($n); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
ternary-cond:0 |
||||
ternary-if:1 |
||||
string(3) "yes" |
||||
int(2) |
||||
match-subject:2 |
||||
match-arm-1:3 |
||||
match-arm-2:4 |
||||
match-body-2:5 |
||||
string(3) "two" |
||||
int(6) |
||||
@ -0,0 +1,19 @@ |
||||
--TEST-- |
||||
exit inside finally should terminate without graceful-exit fatal |
||||
--ENV-- |
||||
USE_ZEND_ALLOC=0 |
||||
--FILE-- |
||||
<?php |
||||
|
||||
try { |
||||
echo "try\n"; |
||||
} finally { |
||||
echo "finally\n"; |
||||
exit(0); |
||||
} |
||||
|
||||
echo "unreachable\n"; |
||||
?> |
||||
--EXPECT-- |
||||
try |
||||
finally |
||||
@ -0,0 +1,31 @@ |
||||
--TEST-- |
||||
unpack followed by named argument should use dynamic call semantics |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function unpack_named_target($a, $b = 20, $c = 30, ...$rest) { |
||||
var_dump($a, $b, $c, $rest); |
||||
} |
||||
|
||||
function main() { |
||||
unpack_named_target(...[10], c: 300, extra: 400); |
||||
|
||||
$fn = 'unpack_named_target'; |
||||
$fn(...[11], c: 301, extra: 401); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(10) |
||||
int(20) |
||||
int(300) |
||||
array(1) { |
||||
["extra"]=> |
||||
int(400) |
||||
} |
||||
int(11) |
||||
int(20) |
||||
int(301) |
||||
array(1) { |
||||
["extra"]=> |
||||
int(401) |
||||
} |
||||
@ -0,0 +1,40 @@ |
||||
--TEST-- |
||||
nested object property array writes use generic property path |
||||
--FILE-- |
||||
<?php |
||||
|
||||
class NestedPropertyArrayWriteBlock |
||||
{ |
||||
public array $predecessors = []; |
||||
public array $phi = []; |
||||
} |
||||
|
||||
class NestedPropertyArrayWriteGraph |
||||
{ |
||||
/** @var array<int, NestedPropertyArrayWriteBlock> */ |
||||
public array $blocks = []; |
||||
|
||||
public function run(): void |
||||
{ |
||||
$this->blocks[1] = new NestedPropertyArrayWriteBlock(); |
||||
$this->blocks[1]->predecessors[] = 42; |
||||
$this->blocks[1]->phi['x'] = 7; |
||||
|
||||
var_dump($this->blocks[1]->predecessors); |
||||
var_dump($this->blocks[1]->phi); |
||||
} |
||||
} |
||||
|
||||
function main() { |
||||
(new NestedPropertyArrayWriteGraph())->run(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
array(1) { |
||||
[0]=> |
||||
int(42) |
||||
} |
||||
array(1) { |
||||
["x"]=> |
||||
int(7) |
||||
} |
||||
@ -0,0 +1,33 @@ |
||||
--TEST-- |
||||
object property null and unset should both behave as false |
||||
--FILE-- |
||||
<?php |
||||
|
||||
class NullUnsetFalseBox |
||||
{ |
||||
public $value = 1; |
||||
} |
||||
|
||||
function main() { |
||||
$box = new NullUnsetFalseBox(); |
||||
|
||||
var_dump((bool) $box->value); |
||||
|
||||
$box->value = null; |
||||
var_dump((bool) $box->value); |
||||
var_dump(isset($box->value)); |
||||
var_dump(empty($box->value)); |
||||
|
||||
$box->value = 1; |
||||
unset($box->value); |
||||
var_dump(isset($box->value)); |
||||
var_dump(empty($box->value)); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
bool(true) |
||||
bool(false) |
||||
bool(false) |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
@ -0,0 +1,57 @@ |
||||
--TEST-- |
||||
object property array writes embedded in expressions should write once |
||||
--FILE-- |
||||
<?php |
||||
|
||||
class PropertyArrayWriteComposedNode |
||||
{ |
||||
public array $items = []; |
||||
} |
||||
|
||||
class PropertyArrayWriteComposedBox |
||||
{ |
||||
public PropertyArrayWriteComposedNode $node; |
||||
|
||||
public function __construct() |
||||
{ |
||||
$this->node = new PropertyArrayWriteComposedNode(); |
||||
} |
||||
} |
||||
|
||||
function next_value(&$counter) { |
||||
echo 'next:' . $counter . "\n"; |
||||
return ++$counter; |
||||
} |
||||
|
||||
function main() { |
||||
$box = new PropertyArrayWriteComposedBox(); |
||||
$counter = 0; |
||||
|
||||
$a = ($box->node->items[] = next_value($counter)); |
||||
$b = true ? ($box->node->items['k'] = next_value($counter)) : 99; |
||||
$c = match ($counter) { |
||||
2 => ($box->node->items[] = next_value($counter)), |
||||
default => 0, |
||||
}; |
||||
|
||||
var_dump($a, $b, $c); |
||||
var_dump($box->node->items); |
||||
var_dump($counter); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
next:0 |
||||
next:1 |
||||
next:2 |
||||
int(1) |
||||
int(2) |
||||
int(3) |
||||
array(3) { |
||||
[0]=> |
||||
int(1) |
||||
["k"]=> |
||||
int(2) |
||||
[1]=> |
||||
int(3) |
||||
} |
||||
int(3) |
||||
Loading…
Reference in new issue