Skip to content

Commit a79c70f

Browse files
authored
[RFC] Convert exit (and die) from language constructs to functions (#13483)
RFC: https://wiki.php.net/rfc/exit-as-function
1 parent 0217784 commit a79c70f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1839
-1342
lines changed

Zend/Optimizer/block_pass.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
868868
break;
869869

870870
case ZEND_RETURN:
871-
case ZEND_EXIT:
872871
if (opline->op1_type == IS_TMP_VAR) {
873872
src = VAR_SOURCE(opline->op1);
874873
if (src && src->opcode == ZEND_QM_ASSIGN) {
@@ -1221,8 +1220,7 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
12211220
target = op_array->opcodes + target_block->start;
12221221
if ((target->opcode == ZEND_RETURN ||
12231222
target->opcode == ZEND_RETURN_BY_REF ||
1224-
target->opcode == ZEND_GENERATOR_RETURN ||
1225-
target->opcode == ZEND_EXIT) &&
1223+
target->opcode == ZEND_GENERATOR_RETURN) &&
12261224
!(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
12271225
/* JMP L, L: RETURN to immediate RETURN */
12281226
*last_op = *target;

Zend/Optimizer/pass1.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
331331
case ZEND_RETURN:
332332
case ZEND_RETURN_BY_REF:
333333
case ZEND_GENERATOR_RETURN:
334-
case ZEND_EXIT:
335334
case ZEND_THROW:
336335
case ZEND_MATCH_ERROR:
337336
case ZEND_CATCH:

Zend/Optimizer/pass3.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ void zend_optimizer_pass3(zend_op_array *op_array, zend_optimizer_ctx *ctx)
8888
MAKE_NOP(opline);
8989
} else if ((target->opcode == ZEND_RETURN ||
9090
target->opcode == ZEND_RETURN_BY_REF ||
91-
target->opcode == ZEND_GENERATOR_RETURN ||
92-
target->opcode == ZEND_EXIT) &&
91+
target->opcode == ZEND_GENERATOR_RETURN) &&
9392
!(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
9493
/* JMP L, L: RETURN to immediate RETURN */
9594
*opline = *target;

Zend/Optimizer/zend_call_graph.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,6 @@ ZEND_API void zend_analyze_calls(zend_arena **arena, zend_script *script, uint32
162162
call_info->send_unpack = 1;
163163
}
164164
break;
165-
case ZEND_EXIT:
166-
/* In this case the DO_CALL opcode may have been dropped
167-
* and caller_call_opline will be NULL. */
168-
break;
169165
}
170166
opline++;
171167
}

Zend/Optimizer/zend_cfg.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,6 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
302302
}
303303
break;
304304
case ZEND_MATCH_ERROR:
305-
case ZEND_EXIT:
306305
case ZEND_THROW:
307306
/* Don't treat THROW as terminator if it's used in expression context,
308307
* as we may lose live ranges when eliminating unreachable code. */
@@ -506,7 +505,6 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
506505
case ZEND_RETURN:
507506
case ZEND_RETURN_BY_REF:
508507
case ZEND_GENERATOR_RETURN:
509-
case ZEND_EXIT:
510508
case ZEND_THROW:
511509
case ZEND_MATCH_ERROR:
512510
case ZEND_VERIFY_NEVER_TYPE:

Zend/tests/arginfo_zpp_mismatch.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ function skipFunction($function): bool {
66
|| $function === 'readline'
77
|| $function === 'readline_read_history'
88
|| $function === 'readline_write_history'
9+
/* terminates script */
10+
|| $function === 'exit'
11+
|| $function === 'die'
912
/* intentionally violate invariants */
1013
|| $function === 'zend_create_unterminated_string'
1114
|| $function === 'zend_test_array_return'

Zend/tests/die_string_cast_exception.phpt

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Printing AST of die "constant" via assert
3+
--INI--
4+
zend.assertions=1
5+
--FILE--
6+
<?php
7+
8+
try {
9+
assert(0 && die);
10+
} catch (Throwable $e) {
11+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
12+
}
13+
14+
?>
15+
--EXPECT--
16+
AssertionError: assert(0 && \exit())
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Printing AST of die function via assert
3+
--INI--
4+
zend.assertions=1
5+
--FILE--
6+
<?php
7+
8+
try {
9+
assert(0 && die());
10+
} catch (Throwable $e) {
11+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
12+
}
13+
14+
?>
15+
--EXPECT--
16+
AssertionError: assert(0 && \exit())
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Printing AST of exit "constant" via assert
3+
--INI--
4+
zend.assertions=1
5+
--FILE--
6+
<?php
7+
8+
try {
9+
assert(0 && exit);
10+
} catch (Throwable $e) {
11+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
12+
}
13+
14+
?>
15+
--EXPECT--
16+
AssertionError: assert(0 && \exit())
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Printing AST of exit function via assert
3+
--INI--
4+
zend.assertions=1
5+
--FILE--
6+
<?php
7+
8+
try {
9+
assert(0 && exit());
10+
} catch (Throwable $e) {
11+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
12+
}
13+
14+
?>
15+
--EXPECT--
16+
AssertionError: assert(0 && \exit())
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
Can define die and exit as class methods, constants and property
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public $exit;
8+
public $die;
9+
10+
const die = 5;
11+
const exit = 10;
12+
13+
public function exit() {
14+
return 20;
15+
}
16+
17+
public function die() {
18+
return 15;
19+
}
20+
}
21+
22+
var_dump(Foo::die);
23+
var_dump(Foo::exit);
24+
$o = new Foo();
25+
var_dump($o->exit);
26+
var_dump($o->die);
27+
var_dump($o->exit());
28+
var_dump($o->die());
29+
30+
?>
31+
--EXPECT--
32+
int(5)
33+
int(10)
34+
NULL
35+
NULL
36+
int(20)
37+
int(15)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Attempting to define die constant
3+
--FILE--
4+
<?php
5+
6+
const die = 5;
7+
8+
var_dump(die);
9+
10+
?>
11+
--EXPECTF--
12+
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Attempting to define die constant in a namespace
3+
--FILE--
4+
<?php
5+
6+
namespace Foo;
7+
8+
const die = 5;
9+
10+
var_dump(die);
11+
12+
?>
13+
--EXPECTF--
14+
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Attempting to define die() function
3+
--FILE--
4+
<?php
5+
6+
function die() { }
7+
8+
?>
9+
--EXPECTF--
10+
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Attempting to define die() function in a namespace
3+
--FILE--
4+
<?php
5+
6+
namespace Foo;
7+
8+
function die() { }
9+
10+
var_dump(die());
11+
12+
?>
13+
--EXPECTF--
14+
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Attempting to define exit constant
3+
--FILE--
4+
<?php
5+
6+
const exit = 5;
7+
8+
var_dump(exit);
9+
10+
?>
11+
--EXPECTF--
12+
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Attempting to define exit constant in a namespace
3+
--FILE--
4+
<?php
5+
6+
namespace Foo;
7+
8+
const exit = 5;
9+
10+
var_dump(exit);
11+
12+
?>
13+
--EXPECTF--
14+
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Attempting to define exit() function
3+
--FILE--
4+
<?php
5+
6+
function exit() { }
7+
8+
?>
9+
--EXPECTF--
10+
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Attempting to define exit() function in a namespace
3+
--FILE--
4+
<?php
5+
6+
namespace Foo;
7+
8+
function exit() { }
9+
10+
?>
11+
--EXPECTF--
12+
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Attempting to define a goto label called die
3+
--FILE--
4+
<?php
5+
6+
echo "Before\n";
7+
8+
echo "In between\n";
9+
die:
10+
echo "After\n";
11+
12+
?>
13+
--EXPECTF--
14+
Parse error: syntax error, unexpected token ":" in %s on line %d
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Attempting to define a goto label called die and jump to it
3+
--FILE--
4+
<?php
5+
6+
echo "Before\n";
7+
goto die;
8+
echo "In between\n";
9+
die:
10+
echo "After\n";
11+
12+
?>
13+
--EXPECTF--
14+
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Attempting to define a goto label called exit
3+
--FILE--
4+
<?php
5+
6+
echo "Before\n";
7+
8+
echo "In between\n";
9+
exit:
10+
echo "After\n";
11+
12+
?>
13+
--EXPECTF--
14+
Parse error: syntax error, unexpected token ":" in %s on line %d
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Attempting to define a goto label called exit and jump to it
3+
--FILE--
4+
<?php
5+
6+
echo "Before\n";
7+
goto exit;
8+
echo "In between\n";
9+
exit:
10+
echo "After\n";
11+
12+
?>
13+
--EXPECTF--
14+
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Bug #79777: String cast exception during die should be handled gracefully
3+
--FILE--
4+
<?php
5+
6+
try {
7+
die(new stdClass);
8+
} catch (TypeError $e) {
9+
echo $e->getMessage(), PHP_EOL;
10+
}
11+
12+
?>
13+
--EXPECT--
14+
exit(): Argument #1 ($code) must be of type string|int, stdClass given

Zend/tests/exit/disabling_die.phpt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Using disable_functions INI to remove die
3+
--INI--
4+
disable_functions=die
5+
--FILE--
6+
<?php
7+
8+
die();
9+
10+
?>
11+
--EXPECT--
12+
Warning: Cannot disable function die() in Unknown on line 0

Zend/tests/exit/disabling_exit.phpt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Using disable_functions INI to remove exit
3+
--INI--
4+
disable_functions=exit
5+
--FILE--
6+
<?php
7+
8+
exit();
9+
10+
?>
11+
--EXPECT--
12+
Warning: Cannot disable function exit() in Unknown on line 0

0 commit comments

Comments
 (0)