@@ -54,6 +54,18 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_znode(znode *node) {
5454 return (zend_ast * ) ast ;
5555}
5656
57+ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc (void ) {
58+ zend_ast_fcc * ast ;
59+
60+ ast = zend_ast_alloc (sizeof (zend_ast_fcc ));
61+ ast -> kind = ZEND_AST_CALLABLE_CONVERT ;
62+ ast -> attr = 0 ;
63+ ast -> lineno = ZEND_MAP_PTR_NEW_OFFSET ();
64+ ZEND_MAP_PTR_NEW (ast -> fptr );
65+
66+ return (zend_ast * ) ast ;
67+ }
68+
5769static zend_always_inline zend_ast * zend_ast_create_zval_int (zval * zv , uint32_t attr , uint32_t lineno ) {
5870 zend_ast_zval * ast ;
5971
@@ -1009,81 +1021,96 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
10091021 switch (ast -> kind ) {
10101022 case ZEND_AST_CALL : {
10111023 ZEND_ASSERT (ast -> child [1 ]-> kind == ZEND_AST_CALLABLE_CONVERT );
1024+ zend_ast_fcc * fcc_ast = (zend_ast_fcc * )ast -> child [1 ];
1025+ fptr = ZEND_MAP_PTR_GET (fcc_ast -> fptr );
10121026
1013- zend_string * function_name = zend_ast_get_str (ast -> child [0 ]);
1014- zend_string * function_name_lc = zend_string_tolower (function_name );
1015- fptr = zend_fetch_function (function_name_lc );
1016- if (!fptr && ast -> child [0 ]-> attr != ZEND_NAME_FQ ) {
1017- const char * backslash = zend_memrchr (ZSTR_VAL (function_name_lc ), '\\' , ZSTR_LEN (function_name_lc ));
1018- if (backslash ) {
1019- fptr = zend_fetch_function_str (backslash + 1 , ZSTR_LEN (function_name_lc ) - (backslash - ZSTR_VAL (function_name_lc ) + 1 ));
1020- }
1021- }
1022- zend_string_release (function_name_lc );
10231027 if (!fptr ) {
1024- zend_throw_error (NULL , "Call to undefined function %s()" , ZSTR_VAL (function_name ));
1025- return FAILURE ;
1028+ zend_string * function_name = zend_ast_get_str (ast -> child [0 ]);
1029+ zend_string * function_name_lc = zend_string_tolower (function_name );
1030+ fptr = zend_fetch_function (function_name_lc );
1031+ if (!fptr && ast -> child [0 ]-> attr != ZEND_NAME_FQ ) {
1032+ const char * backslash = zend_memrchr (ZSTR_VAL (function_name_lc ), '\\' , ZSTR_LEN (function_name_lc ));
1033+ if (backslash ) {
1034+ fptr = zend_fetch_function_str (backslash + 1 , ZSTR_LEN (function_name_lc ) - (backslash - ZSTR_VAL (function_name_lc ) + 1 ));
1035+ }
1036+ }
1037+ zend_string_release (function_name_lc );
1038+ if (!fptr ) {
1039+ zend_throw_error (NULL , "Call to undefined function %s()" , ZSTR_VAL (function_name ));
1040+ return FAILURE ;
1041+ }
1042+
1043+ ZEND_MAP_PTR_SET (fcc_ast -> fptr , fptr );
10261044 }
1045+
10271046 break ;
10281047 }
10291048 case ZEND_AST_STATIC_CALL : {
10301049 ZEND_ASSERT (ast -> child [2 ]-> kind == ZEND_AST_CALLABLE_CONVERT );
1050+ zend_ast_fcc * fcc_ast = (zend_ast_fcc * )ast -> child [2 ];
10311051
1032- zend_class_entry * ce = zend_ast_fetch_class (ast -> child [0 ], scope );
1033- if (!ce ) {
1034- return FAILURE ;
1035- }
1036- zend_string * method_name = zend_ast_get_str (ast -> child [1 ]);
1037- if (ce -> get_static_method ) {
1038- fptr = ce -> get_static_method (ce , method_name );
1039- } else {
1040- fptr = zend_hash_find_ptr_lc (& ce -> function_table , method_name );
1041- if (fptr ) {
1042- if (!(fptr -> common .fn_flags & ZEND_ACC_PUBLIC )) {
1043- if (UNEXPECTED (fptr -> common .scope != scope )) {
1044- if (
1045- UNEXPECTED (fptr -> op_array .fn_flags & ZEND_ACC_PRIVATE )
1046- || UNEXPECTED (!zend_check_protected (zend_get_function_root_class (fptr ), scope ))
1047- ) {
1048- if (ce -> __callstatic ) {
1049- zend_throw_error (NULL , "Creating a callable for the magic __callStatic() method is not supported in constant expressions" );
1050- } else {
1051- zend_bad_method_call (fptr , method_name , scope );
1052- }
1052+ fptr = ZEND_MAP_PTR_GET (fcc_ast -> fptr );
10531053
1054- return FAILURE ;
1054+ if (!fptr ) {
1055+ zend_class_entry * ce = zend_ast_fetch_class (ast -> child [0 ], scope );
1056+ if (!ce ) {
1057+ return FAILURE ;
1058+ }
1059+ zend_string * method_name = zend_ast_get_str (ast -> child [1 ]);
1060+ if (ce -> get_static_method ) {
1061+ fptr = ce -> get_static_method (ce , method_name );
1062+ } else {
1063+ fptr = zend_hash_find_ptr_lc (& ce -> function_table , method_name );
1064+ if (fptr ) {
1065+ if (!(fptr -> common .fn_flags & ZEND_ACC_PUBLIC )) {
1066+ if (UNEXPECTED (fptr -> common .scope != scope )) {
1067+ if (
1068+ UNEXPECTED (fptr -> op_array .fn_flags & ZEND_ACC_PRIVATE )
1069+ || UNEXPECTED (!zend_check_protected (zend_get_function_root_class (fptr ), scope ))
1070+ ) {
1071+ if (ce -> __callstatic ) {
1072+ zend_throw_error (NULL , "Creating a callable for the magic __callStatic() method is not supported in constant expressions" );
1073+ } else {
1074+ zend_bad_method_call (fptr , method_name , scope );
1075+ }
1076+
1077+ return FAILURE ;
1078+ }
10551079 }
10561080 }
1057- }
1058- } else {
1059- if (ce -> __callstatic ) {
1060- zend_throw_error (NULL , "Creating a callable for the magic __callStatic() method is not supported in constant expressions" );
10611081 } else {
1062- zend_undefined_method (ce , method_name );
1082+ if (ce -> __callstatic ) {
1083+ zend_throw_error (NULL , "Creating a callable for the magic __callStatic() method is not supported in constant expressions" );
1084+ } else {
1085+ zend_undefined_method (ce , method_name );
1086+ }
1087+
1088+ return FAILURE ;
10631089 }
1090+ }
10641091
1092+ if (!(fptr -> common .fn_flags & ZEND_ACC_STATIC )) {
1093+ zend_non_static_method_call (fptr );
1094+
10651095 return FAILURE ;
10661096 }
1067- }
1068-
1069- if (!(fptr -> common .fn_flags & ZEND_ACC_STATIC )) {
1070- zend_non_static_method_call (fptr );
1071-
1072- return FAILURE ;
1073- }
1074- if ((fptr -> common .fn_flags & ZEND_ACC_ABSTRACT )) {
1075- zend_abstract_method_call (fptr );
1076-
1077- return FAILURE ;
1078- } else if (fptr -> common .scope -> ce_flags & ZEND_ACC_TRAIT ) {
1079- zend_error (E_DEPRECATED ,
1080- "Calling static trait method %s::%s is deprecated, "
1081- "it should only be called on a class using the trait" ,
1082- ZSTR_VAL (fptr -> common .scope -> name ), ZSTR_VAL (fptr -> common .function_name ));
1083- if (EG (exception )) {
1097+ if ((fptr -> common .fn_flags & ZEND_ACC_ABSTRACT )) {
1098+ zend_abstract_method_call (fptr );
1099+
10841100 return FAILURE ;
1101+ } else if (fptr -> common .scope -> ce_flags & ZEND_ACC_TRAIT ) {
1102+ zend_error (E_DEPRECATED ,
1103+ "Calling static trait method %s::%s is deprecated, "
1104+ "it should only be called on a class using the trait" ,
1105+ ZSTR_VAL (fptr -> common .scope -> name ), ZSTR_VAL (fptr -> common .function_name ));
1106+ if (EG (exception )) {
1107+ return FAILURE ;
1108+ }
10851109 }
1110+
1111+ ZEND_MAP_PTR_SET (fcc_ast -> fptr , fptr );
10861112 }
1113+
10871114 break ;
10881115 }
10891116 }
@@ -1182,6 +1209,8 @@ static size_t ZEND_FASTCALL zend_ast_tree_size(zend_ast *ast)
11821209 size = sizeof (zend_ast_zval );
11831210 } else if (ast -> kind == ZEND_AST_OP_ARRAY ) {
11841211 size = sizeof (zend_ast_op_array );
1212+ } else if (ast -> kind == ZEND_AST_CALLABLE_CONVERT ) {
1213+ size = sizeof (zend_ast_fcc );
11851214 } else if (zend_ast_is_list (ast )) {
11861215 uint32_t i ;
11871216 zend_ast_list * list = zend_ast_get_list (ast );
@@ -1249,6 +1278,13 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
12491278 new -> lineno = old -> lineno ;
12501279 new -> op_array = old -> op_array ;
12511280 buf = (void * )((char * )buf + sizeof (zend_ast_op_array ));
1281+ } else if (ast -> kind == ZEND_AST_CALLABLE_CONVERT ) {
1282+ zend_ast_fcc * new = (zend_ast_fcc * )buf ;
1283+ new -> kind = ZEND_AST_CALLABLE_CONVERT ;
1284+ new -> attr = ast -> attr ;
1285+ new -> lineno = ast -> lineno ;
1286+ new -> fptr__ptr = ((zend_ast_fcc * ) ast )-> fptr__ptr ;
1287+ buf = (void * )((char * )buf + sizeof (zend_ast_fcc ));
12521288 } else if (zend_ast_is_decl (ast )) {
12531289 /* Not implemented. */
12541290 ZEND_UNREACHABLE ();
0 commit comments