Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8cb302a

Browse files
Allow arbitrary expressions in static variable initializer
1 parent 1fb40b5 commit 8cb302a

23 files changed

+873
-598
lines changed

‎Zend/tests/035.phpt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Using 'static' and 'global' in global scope
33
--FILE--
44
<?php
55

6-
static $var, $var, $var = -1;
6+
static $var = -1;
77
var_dump($var);
88

99
global $var, $var, $var;

‎Zend/tests/bug79778.phpt‎

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,49 @@ Bug #79778: Assertion failure if dumping closure with unresolved static variable
55
$closure1 = function() {
66
static $var = CONST_REF;
77
};
8+
9+
var_dump($closure1);
10+
print_r($closure1);
11+
12+
try {
13+
$closure1();
14+
} catch (\Error $e) {
15+
echo $e->getMessage(), "\n";
16+
}
17+
18+
var_dump($closure1);
19+
print_r($closure1);
20+
21+
const CONST_REF = 'foo';
22+
$closure1();
823
var_dump($closure1);
924
print_r($closure1);
25+
1026
?>
1127
--EXPECT--
28+
object(Closure)#1 (0) {
29+
}
30+
Closure Object
31+
(
32+
)
33+
Undefined constant "CONST_REF"
34+
object(Closure)#1 (0) {
35+
}
36+
Closure Object
37+
(
38+
)
1239
object(Closure)#1 (1) {
1340
["static"]=>
1441
array(1) {
1542
["var"]=>
16-
string(14) "<constant ast>"
43+
string(3) "foo"
1744
}
1845
}
1946
Closure Object
2047
(
2148
[static] => Array
2249
(
23-
[var] => <constant ast>
50+
[var] => foo
2451
)
2552

2653
)
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
--TEST--
2-
New with anonymous class is not supported in constant expressions
2+
New with anonymous class works
33
--FILE--
44
<?php
55

66
static $x = new class {};
77

8+
var_dump($x);
9+
810
?>
9-
--EXPECTF--
10-
Fatal error: Cannot use anonymous class in constant expression in %s on line %d
11+
--EXPECT--
12+
object(class@anonymous)#1 (0) {
13+
}
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
--TEST--
2-
Argument unpacking in new arguments in const expr (not yet supported)
2+
Argument unpacking in new arguments in static variable
33
--FILE--
44
<?php
55

66
static $x = new stdClass(...[0]);
77

8+
var_dump($x);
9+
810
?>
9-
--EXPECTF--
10-
Fatal error: Argument unpacking in constant expressions is not supported in %s on line %d
11+
--EXPECT--
12+
object(stdClass)#1 (0) {
13+
}

‎Zend/tests/constexpr/new_dynamic_class_name.phpt‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@ Dynamic class name in new is not supported
33
--FILE--
44
<?php
55

6+
class Foo {}
7+
const FOO = 'Foo';
68
static $x = new (FOO);
79

10+
var_dump($x);
11+
812
?>
9-
--EXPECTF--
10-
Fatal error: Cannot use dynamic class name in constant expression in %s on line %d
13+
--EXPECT--
14+
object(Foo)#1 (0) {
15+
}

‎Zend/tests/constexpr/new_invalid_operation_in_arg.phpt‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,17 @@ Invalid operation in new arg in const expr
33
--FILE--
44
<?php
55

6+
$foo = [1, 2, 3];
67
static $x = new stdClass($foo);
8+
var_dump($foo);
79

810
?>
9-
--EXPECTF--
10-
Fatal error: Constant expression contains invalid operations in %s on line %d
11+
--EXPECT--
12+
array(3) {
13+
[0]=>
14+
int(1)
15+
[1]=>
16+
int(2)
17+
[2]=>
18+
int(3)
19+
}

‎Zend/tests/constexpr/new_static.phpt‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,20 @@ Static in new is not supported
33
--FILE--
44
<?php
55

6-
static $x = new static;
6+
class Foo {
7+
public static function singleton() {
8+
static $x = new static;
9+
return $x;
10+
}
11+
}
12+
13+
$x = Foo::singleton();
14+
$y = Foo::singleton();
15+
var_dump($x, $y);
716

817
?>
9-
--EXPECTF--
10-
Fatal error: "static" is not allowed in compile-time constants in %s on line %d
18+
--EXPECT--
19+
object(Foo)#1 (0) {
20+
}
21+
object(Foo)#1 (0) {
22+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
Static variable initializer with function call
3+
--FILE--
4+
<?php
5+
6+
function bar() {
7+
echo "bar() called\n";
8+
return 'bar';
9+
}
10+
11+
function foo() {
12+
static $bar = bar();
13+
echo $bar, "\n";
14+
}
15+
16+
foo();
17+
foo();
18+
19+
?>
20+
--EXPECT--
21+
bar() called
22+
bar
23+
bar

‎Zend/zend_compile.c‎

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,6 +2174,7 @@ static inline void zend_update_jump_target(uint32_t opnum_jump, uint32_t opnum_t
21742174
zend_op *opline = &CG(active_op_array)->opcodes[opnum_jump];
21752175
switch (opline->opcode) {
21762176
case ZEND_JMP:
2177+
case ZEND_JMP_STATIC_DEF:
21772178
opline->op1.opline_num = opnum_target;
21782179
break;
21792180
case ZEND_JMPZ:
@@ -4778,16 +4779,53 @@ static void zend_compile_static_var_common(zend_string *var_name, zval *value, u
47784779
static void zend_compile_static_var(zend_ast *ast) /* {{{ */
47794780
{
47804781
zend_ast *var_ast = ast->child[0];
4781-
zend_ast **value_ast_ptr = &ast->child[1];
4782-
zvalvalue_zv;
4782+
zend_ast *value_ast = ast->child[1];
4783+
zend_string*var_name=zend_ast_get_str(var_ast);
47834784

4784-
if (*value_ast_ptr) {
4785-
zend_const_expr_to_zval(&value_zv, value_ast_ptr, /* allow_dynamic */ true);
4786-
} else {
4787-
ZVAL_NULL(&value_zv);
4785+
if (zend_string_equals_literal(var_name, "this")) {
4786+
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable");
47884787
}
47894788

4790-
zend_compile_static_var_common(zend_ast_get_str(var_ast), &value_zv, ZEND_BIND_REF);
4789+
if (!value_ast) {
4790+
zval value_zv;
4791+
ZVAL_NULL(&value_zv);
4792+
zend_compile_static_var_common(zend_ast_get_str(var_ast), &value_zv, ZEND_BIND_REF);
4793+
} else {
4794+
zend_op *opline;
4795+
4796+
if (!CG(active_op_array)->static_variables) {
4797+
if (CG(active_op_array)->scope) {
4798+
CG(active_op_array)->scope->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
4799+
}
4800+
CG(active_op_array)->static_variables = zend_new_array(8);
4801+
}
4802+
4803+
if (zend_hash_exists(CG(active_op_array)->static_variables, var_name)) {
4804+
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate declaration of static variable $%s", ZSTR_VAL(var_name));
4805+
}
4806+
4807+
zval placeholder;
4808+
ZVAL_UNDEF(&placeholder);
4809+
zval *placeholder_ptr = zend_hash_update(CG(active_op_array)->static_variables, var_name, &placeholder);
4810+
uint32_t placeholder_offset = (uint32_t)((char*)placeholder_ptr - (char*)CG(active_op_array)->static_variables->arData);
4811+
4812+
uint32_t jmp_opnum = get_next_op_number();
4813+
opline = zend_emit_op(NULL, ZEND_JMP_STATIC_DEF, NULL, NULL);
4814+
opline->extended_value = placeholder_offset;
4815+
4816+
znode expr;
4817+
zend_compile_expr(&expr, value_ast);
4818+
4819+
opline = zend_emit_op(NULL, ZEND_ASSIGN_STATIC, &expr, NULL);
4820+
opline->extended_value = placeholder_offset;
4821+
4822+
zend_update_jump_target_to_next(jmp_opnum);
4823+
4824+
opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, NULL);
4825+
opline->op1_type = IS_CV;
4826+
opline->op1.var = lookup_cv(var_name);
4827+
opline->extended_value = placeholder_offset | ZEND_BIND_REF;
4828+
}
47914829
}
47924830
/* }}} */
47934831

‎Zend/zend_opcode.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,7 @@ ZEND_API void pass_two(zend_op_array *op_array)
11031103
}
11041104
ZEND_FALLTHROUGH;
11051105
case ZEND_JMP:
1106+
case ZEND_JMP_STATIC_DEF:
11061107
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
11071108
break;
11081109
case ZEND_JMPZ:

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /