Skip to content

Commit bc6df63

Browse files
committed
fixup! Support first-class callables in const-expressions
1 parent bb8f4b3 commit bc6df63

File tree

5 files changed

+60
-8
lines changed

5 files changed

+60
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
FCC in initializer errors for FCC on 'static::'.
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public const Closure = static::myMethod(...);
8+
9+
public static function myMethod(string $foo) {
10+
echo "Called ", __METHOD__, PHP_EOL;
11+
var_dump($foo);
12+
}
13+
}
14+
15+
var_dump(Foo::Closure);
16+
(Foo::Closure)("abc");
17+
18+
?>
19+
--EXPECTF--
20+
Fatal error: "static" is not allowed in compile-time constants in %s on line %d

Zend/tests/closure_const_expr/fcc/static_call.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
Allow defining FCC for userland functions in const expressions.
2+
Allow defining FCC for static methods in const expressions.
33
--FILE--
44
<?php
55

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
Allow defining FCC for static methods referenced by 'self::' in const expressions.
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public const Closure = self::myMethod(...);
8+
9+
public static function myMethod(string $foo) {
10+
echo "Called ", __METHOD__, PHP_EOL;
11+
var_dump($foo);
12+
}
13+
}
14+
15+
var_dump(Foo::Closure);
16+
(Foo::Closure)("abc");
17+
18+
?>
19+
--EXPECTF--
20+
object(Closure)#%d (2) {
21+
["function"]=>
22+
string(13) "Foo::myMethod"
23+
["parameter"]=>
24+
array(1) {
25+
["$foo"]=>
26+
string(10) "<required>"
27+
}
28+
}
29+
Called Foo::myMethod
30+
string(3) "abc"

Zend/zend_ast.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -1009,8 +1009,7 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
10091009
case ZEND_AST_STATIC_CALL: {
10101010
ZEND_ASSERT(ast->child[2]->kind == ZEND_AST_CALLABLE_CONVERT);
10111011

1012-
zend_string *class_name = zend_ast_get_str(ast->child[0]);
1013-
zend_class_entry *ce = zend_fetch_class_with_scope(class_name, (ast->attr >> ZEND_CONST_EXPR_NEW_FETCH_TYPE_SHIFT) | ZEND_FETCH_CLASS_EXCEPTION, scope);
1012+
zend_class_entry *ce = zend_ast_fetch_class(ast->child[0], scope);
10141013
if (!ce) {
10151014
return FAILURE;
10161015
}

Zend/zend_compile.c

+8-5
Original file line numberDiff line numberDiff line change
@@ -11182,9 +11182,8 @@ static void zend_compile_const_expr_magic_const(zend_ast **ast_ptr) /* {{{ */
1118211182
}
1118311183
/* }}} */
1118411184

11185-
static void zend_compile_const_expr_new(zend_ast **ast_ptr)
11185+
static void zend_compile_const_expr_class_reference(zend_ast *class_ast)
1118611186
{
11187-
zend_ast *class_ast = (*ast_ptr)->child[0];
1118811187
if (class_ast->kind == ZEND_AST_CLASS) {
1118911188
zend_error_noreturn(E_COMPILE_ERROR,
1119011189
"Cannot use anonymous class in constant expression");
@@ -11207,6 +11206,12 @@ static void zend_compile_const_expr_new(zend_ast **ast_ptr)
1120711206
class_ast->attr = fetch_type << ZEND_CONST_EXPR_NEW_FETCH_TYPE_SHIFT;
1120811207
}
1120911208

11209+
static void zend_compile_const_expr_new(zend_ast **ast_ptr)
11210+
{
11211+
zend_ast *class_ast = (*ast_ptr)->child[0];
11212+
zend_compile_const_expr_class_reference(class_ast);
11213+
}
11214+
1121011215
static void zend_compile_const_expr_closure(zend_ast **ast_ptr)
1121111216
{
1121211217
zend_ast_decl *closure_ast = (zend_ast_decl *) *ast_ptr;
@@ -11256,9 +11261,7 @@ static void zend_compile_const_expr_fcc(zend_ast **ast_ptr)
1125611261
}
1125711262
case ZEND_AST_STATIC_CALL: {
1125811263
zend_ast *class_ast = (*ast_ptr)->child[0];
11259-
if (class_ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(class_ast)) != IS_STRING) {
11260-
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use dynamic class name in constant expression");
11261-
}
11264+
zend_compile_const_expr_class_reference(class_ast);
1126211265
zend_ast *method_ast = (*ast_ptr)->child[1];
1126311266
if (method_ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(method_ast)) != IS_STRING) {
1126411267
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use dynamic method name in constant expression");

0 commit comments

Comments
 (0)