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