diff --git a/NEWS b/NEWS index 8f129d715d873..930dbec180221 100644 --- a/NEWS +++ b/NEWS @@ -59,6 +59,7 @@ PHP NEWS . Added support for `final` with constructor property promotion. (DanielEScherzer) . Do not use RTLD_DEEPBIND if dlmopen is available. (Daniil Gentili) + . Make `clone() a function. (timwolla, edorian) - Curl: . Added curl_multi_get_handles(). (timwolla) diff --git a/UPGRADING b/UPGRADING index 4dca8f2b2c213..98537007f65cd 100644 --- a/UPGRADING +++ b/UPGRADING @@ -374,6 +374,8 @@ PHP 8.5 UPGRADE NOTES . get_exception_handler() allows retrieving the current user-defined exception handler function. RFC: https://wiki.php.net/rfc/get-error-exception-handler + . The clone language construct is now a function. + RFC: https://wiki.php.net/rfc/clone_with_v2 - Curl: . curl_multi_get_handles() allows retrieving all CurlHandles current diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 3655e5fd21c35..c36b7490de62c 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -1,6 +1,7 @@ /* This is a generated file, edit the .stub.php files instead. */ static const func_info_t func_infos[] = { + F1("clone", MAY_BE_OBJECT), F1("zend_version", MAY_BE_STRING), FN("func_get_args", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ANY), F1("get_class_vars", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), diff --git a/Zend/tests/assert/expect_015.phpt b/Zend/tests/assert/expect_015.phpt index 695c4c166a83c..9f8e9b77003bc 100644 --- a/Zend/tests/assert/expect_015.phpt +++ b/Zend/tests/assert/expect_015.phpt @@ -183,7 +183,7 @@ assert(0 && ($a = function () { $x = $a ?? $b; [$a, $b, $c] = [1, 2 => 'x', 'z' => 'c']; @foo(); - $y = clone $x; + $y = \clone($x); yield 1 => 2; yield from $x; })) diff --git a/Zend/tests/clone/ast.phpt b/Zend/tests/clone/ast.phpt new file mode 100644 index 0000000000000..89a1a0a481000 --- /dev/null +++ b/Zend/tests/clone/ast.phpt @@ -0,0 +1,31 @@ +--TEST-- +Ast Printing +--FILE-- +getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone($x)); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone(...)); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +assert(false && ($y = \clone($x))) +assert(false && ($y = \clone($x))) +assert(false && ($y = \clone(...))) diff --git a/Zend/tests/clone/bug36071.phpt b/Zend/tests/clone/bug36071.phpt index 945118fef3754..e1a4baa7226ee 100644 --- a/Zend/tests/clone/bug36071.phpt +++ b/Zend/tests/clone/bug36071.phpt @@ -4,11 +4,11 @@ Bug #36071 (Engine Crash related with 'clone') error_reporting=4095 --FILE-- b = 0; +try { + $a = clone 0; +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} ?> ---EXPECTF-- -Fatal error: Uncaught Error: __clone method called on non-object in %sbug36071.php:2 -Stack trace: -#0 {main} - thrown in %sbug36071.php on line 2 +--EXPECT-- +TypeError: clone(): Argument #1 ($object) must be of type object, int given diff --git a/Zend/tests/clone/bug42817.phpt b/Zend/tests/clone/bug42817.phpt index a681d861d0c8f..b5f53222d7ee5 100644 --- a/Zend/tests/clone/bug42817.phpt +++ b/Zend/tests/clone/bug42817.phpt @@ -2,11 +2,11 @@ Bug #42817 (clone() on a non-object does not result in a fatal error) --FILE-- b, $c); +try { + $a = clone(null); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} ?> ---EXPECTF-- -Fatal error: Uncaught Error: __clone method called on non-object in %sbug42817.php:2 -Stack trace: -#0 {main} - thrown in %sbug42817.php on line 2 +--EXPECT-- +TypeError: clone(): Argument #1 ($object) must be of type object, null given diff --git a/Zend/tests/clone/bug42818.phpt b/Zend/tests/clone/bug42818.phpt index b37ce13fd174a..08ba05fcfaa22 100644 --- a/Zend/tests/clone/bug42818.phpt +++ b/Zend/tests/clone/bug42818.phpt @@ -2,10 +2,11 @@ Bug #42818 ($foo = clone(array()); leaks memory) --FILE-- getMessage(), PHP_EOL; +} ?> ---EXPECTF-- -Fatal error: Uncaught Error: __clone method called on non-object in %sbug42818.php:2 -Stack trace: -#0 {main} - thrown in %sbug42818.php on line 2 +--EXPECT-- +TypeError: clone(): Argument #1 ($object) must be of type object, array given diff --git a/Zend/tests/clone/clone_001.phpt b/Zend/tests/clone/clone_001.phpt index 87024c3cd5614..91fa6f551176d 100644 --- a/Zend/tests/clone/clone_001.phpt +++ b/Zend/tests/clone/clone_001.phpt @@ -3,11 +3,12 @@ Using clone statement on non-object --FILE-- getMessage(), PHP_EOL; +} ?> ---EXPECTF-- -Fatal error: Uncaught Error: __clone method called on non-object in %s:%d -Stack trace: -#0 {main} - thrown in %s on line %d +--EXPECT-- +TypeError: clone(): Argument #1 ($object) must be of type object, array given diff --git a/Zend/tests/clone/clone_003.phpt b/Zend/tests/clone/clone_003.phpt index f163616a876dc..b8bb2833dc257 100644 --- a/Zend/tests/clone/clone_003.phpt +++ b/Zend/tests/clone/clone_003.phpt @@ -3,13 +3,13 @@ Using clone statement on undefined variable --FILE-- getMessage(), PHP_EOL; +} ?> --EXPECTF-- Warning: Undefined variable $b in %s on line %d - -Fatal error: Uncaught Error: __clone method called on non-object in %s:%d -Stack trace: -#0 {main} - thrown in %s on line %d +TypeError: clone(): Argument #1 ($object) must be of type object, null given diff --git a/Zend/tests/clone/clone_005.phpt b/Zend/tests/clone/clone_005.phpt new file mode 100644 index 0000000000000..e0366cae67cb5 --- /dev/null +++ b/Zend/tests/clone/clone_005.phpt @@ -0,0 +1,55 @@ +--TEST-- +Clone as a function. +--FILE-- +clone_me()[0]; + +var_dump($f !== $clone); + +?> +--EXPECTF-- +object(stdClass)#%d (0) { +} +array(3) { + [0]=> + object(stdClass)#%d (0) { + } + [1]=> + object(stdClass)#%d (0) { + } + [2]=> + object(stdClass)#%d (0) { + } +} +array(3) { + [0]=> + object(stdClass)#%d (0) { + } + [1]=> + object(stdClass)#%d (0) { + } + [2]=> + object(stdClass)#%d (0) { + } +} +bool(true) diff --git a/Zend/tests/magic_methods/bug73288.phpt b/Zend/tests/magic_methods/bug73288.phpt index 52e8eedeaf013..5e1334cacd07c 100644 --- a/Zend/tests/magic_methods/bug73288.phpt +++ b/Zend/tests/magic_methods/bug73288.phpt @@ -23,6 +23,7 @@ function test_clone() { $b = clone $c->x; } +// No catch, because we want to test Exception::__toString(). test_clone(); ?> --EXPECTF-- diff --git a/Zend/zend_API.c b/Zend/zend_API.c index d29fe8ae8e3c3..df8b4252c42ad 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3648,6 +3648,7 @@ static void zend_disable_function(const char *function_name, size_t function_nam if (UNEXPECTED( (function_name_length == strlen("exit") && !memcmp(function_name, "exit", strlen("exit"))) || (function_name_length == strlen("die") && !memcmp(function_name, "die", strlen("die"))) + || (function_name_length == strlen("clone") && !memcmp(function_name, "clone", strlen("clone"))) )) { zend_error(E_WARNING, "Cannot disable function %s()", function_name); return; diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index cdc86faa95aa3..728695bd9e930 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -2345,8 +2345,6 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio } smart_str_appendc(str, '`'); break; - case ZEND_AST_CLONE: - PREFIX_OP("clone ", 270, 271); case ZEND_AST_PRINT: PREFIX_OP("print ", 60, 61); case ZEND_AST_INCLUDE_OR_EVAL: diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index c82ca66c9f573..08400cff5dd8e 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -89,7 +89,6 @@ enum _zend_ast_kind { ZEND_AST_ISSET, ZEND_AST_SILENCE, ZEND_AST_SHELL_EXEC, - ZEND_AST_CLONE, ZEND_AST_PRINT, ZEND_AST_INCLUDE_OR_EVAL, ZEND_AST_UNARY_OP, diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 7a07ceadce2e2..48e5c70897294 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -69,6 +69,49 @@ zend_result zend_startup_builtin_functions(void) /* {{{ */ } /* }}} */ +ZEND_FUNCTION(clone) +{ + zend_object *zobj; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ(zobj) + ZEND_PARSE_PARAMETERS_END(); + + /* clone() also exists as the ZEND_CLONE OPcode and both implementations must be kept in sync. */ + + zend_class_entry *scope = zend_get_executed_scope(); + + zend_class_entry *ce = zobj->ce; + zend_function *clone = ce->clone; + + if (UNEXPECTED(zobj->handlers->clone_obj == NULL)) { + zend_throw_error(NULL, "Trying to clone an uncloneable object of class %s", ZSTR_VAL(ce->name)); + RETURN_THROWS(); + } + + if (clone && !(clone->common.fn_flags & ZEND_ACC_PUBLIC)) { + if (clone->common.scope != scope) { + if (UNEXPECTED(clone->common.fn_flags & ZEND_ACC_PRIVATE) + || UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) { + zend_throw_error(NULL, "Call to %s %s::__clone() from %s%s", + zend_visibility_string(clone->common.fn_flags), ZSTR_VAL(clone->common.scope->name), + scope ? "scope " : "global scope", + scope ? ZSTR_VAL(scope->name) : "" + ); + RETURN_THROWS(); + } + } + } + + zend_object *cloned; + cloned = zobj->handlers->clone_obj(zobj); + + ZEND_ASSERT(cloned || EG(exception)); + if (EXPECTED(cloned)) { + RETURN_OBJ(cloned); + } +} + ZEND_FUNCTION(exit) { zend_string *str = NULL; diff --git a/Zend/zend_builtin_functions.stub.php b/Zend/zend_builtin_functions.stub.php index 7f316835aea6b..256c405c71c28 100644 --- a/Zend/zend_builtin_functions.stub.php +++ b/Zend/zend_builtin_functions.stub.php @@ -7,6 +7,9 @@ class stdClass { } +/** @refcount 1 */ +function _clone(object $object): object {} + function exit(string|int $status = 0): never {} /** @alias exit */ diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h index 9498b8292f892..1c595ecd5777c 100644 --- a/Zend/zend_builtin_functions_arginfo.h +++ b/Zend/zend_builtin_functions_arginfo.h @@ -1,5 +1,9 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a24761186f1ddf758e648b0a764826537cbd33b9 */ + * Stub hash: 12327caa3fe940ccef68ed99f9278982dc0173a5 */ + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_clone, 0, 1, IS_OBJECT, 0) + ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) +ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_exit, 0, 0, IS_NEVER, 0) ZEND_ARG_TYPE_MASK(0, status, MAY_BE_STRING|MAY_BE_LONG, "0") @@ -243,6 +247,7 @@ static const zend_frameless_function_info frameless_function_infos_class_exists[ { 0 }, }; +ZEND_FUNCTION(clone); ZEND_FUNCTION(exit); ZEND_FUNCTION(zend_version); ZEND_FUNCTION(func_num_args); @@ -306,6 +311,7 @@ ZEND_FUNCTION(gc_disable); ZEND_FUNCTION(gc_status); static const zend_function_entry ext_functions[] = { + ZEND_FE(clone, arginfo_clone) ZEND_FE(exit, arginfo_exit) ZEND_RAW_FENTRY("die", zif_exit, arginfo_die, 0, NULL, NULL) ZEND_FE(zend_version, arginfo_zend_version) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 28bea1a21d759..f3f6d1b75aec1 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4930,6 +4930,20 @@ static zend_result zend_compile_func_sprintf(znode *result, zend_ast_list *args) return SUCCESS; } +static zend_result zend_compile_func_clone(znode *result, zend_ast_list *args) +{ + znode arg_node; + + if (args->children != 1) { + return FAILURE; + } + + zend_compile_expr(&arg_node, args->child[0]); + zend_emit_op_tmp(result, ZEND_CLONE, &arg_node, NULL); + + return SUCCESS; +} + static zend_result zend_try_compile_special_func_ex(znode *result, zend_string *lcname, zend_ast_list *args, zend_function *fbc, uint32_t type) /* {{{ */ { if (zend_string_equals_literal(lcname, "strlen")) { @@ -4998,6 +5012,8 @@ static zend_result zend_try_compile_special_func_ex(znode *result, zend_string * return zend_compile_func_array_key_exists(result, args); } else if (zend_string_equals_literal(lcname, "sprintf")) { return zend_compile_func_sprintf(result, args); + } else if (zend_string_equals(lcname, ZSTR_KNOWN(ZEND_STR_CLONE))) { + return zend_compile_func_clone(result, args); } else { return FAILURE; } @@ -5391,17 +5407,6 @@ static void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */ } /* }}} */ -static void zend_compile_clone(znode *result, zend_ast *ast) /* {{{ */ -{ - zend_ast *obj_ast = ast->child[0]; - - znode obj_node; - zend_compile_expr(&obj_node, obj_ast); - - zend_emit_op_tmp(result, ZEND_CLONE, &obj_node, NULL); -} -/* }}} */ - static void zend_compile_global_var(zend_ast *ast) /* {{{ */ { zend_ast *var_ast = ast->child[0]; @@ -11717,9 +11722,6 @@ static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */ case ZEND_AST_NEW: zend_compile_new(result, ast); return; - case ZEND_AST_CLONE: - zend_compile_clone(result, ast); - return; case ZEND_AST_ASSIGN_OP: zend_compile_compound_assign(result, ast); return; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 816b8126cbf25..016c6e5c9d098 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1228,7 +1228,16 @@ expr: { $$ = zend_ast_create(ZEND_AST_ASSIGN, $1, $3); } | variable '=' ampersand variable { $$ = zend_ast_create(ZEND_AST_ASSIGN_REF, $1, $4); } - | T_CLONE expr { $$ = zend_ast_create(ZEND_AST_CLONE, $2); } + | T_CLONE '(' T_ELLIPSIS ')' { + zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CLONE)); + name->attr = ZEND_NAME_FQ; + $$ = zend_ast_create(ZEND_AST_CALL, name, zend_ast_create_fcc()); + } + | T_CLONE expr { + zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CLONE)); + name->attr = ZEND_NAME_FQ; + $$ = zend_ast_create(ZEND_AST_CALL, name, zend_ast_create_list(1, ZEND_AST_ARG_LIST, $2)); + } | variable T_PLUS_EQUAL expr { $$ = zend_ast_create_assign_op(ZEND_ADD, $1, $3); } | variable T_MINUS_EQUAL expr diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 0b2a484016ec3..f60e4dec4e71f 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -575,6 +575,7 @@ EMPTY_SWITCH_DEFAULT_CASE() _(ZEND_STR_UNKNOWN, "unknown") \ _(ZEND_STR_UNKNOWN_CAPITALIZED, "Unknown") \ _(ZEND_STR_EXIT, "exit") \ + _(ZEND_STR_CLONE, "clone") \ _(ZEND_STR_EVAL, "eval") \ _(ZEND_STR_INCLUDE, "include") \ _(ZEND_STR_REQUIRE, "require") \ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 617e114dd05db..be7bc8b37b7dd 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6006,6 +6006,8 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY) SAVE_OPLINE(); obj = GET_OP1_OBJ_ZVAL_PTR_UNDEF(BP_VAR_R); + /* ZEND_CLONE also exists as the clone() function and both implementations must be kept in sync. */ + do { if (OP1_TYPE == IS_CONST || (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { @@ -6022,7 +6024,7 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY) HANDLE_EXCEPTION(); } } - zend_throw_error(NULL, "__clone method called on non-object"); + zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj)); FREE_OP1(); HANDLE_EXCEPTION(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 791e4b4e88437..3a13f4244d361 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5180,6 +5180,8 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_ SAVE_OPLINE(); obj = RT_CONSTANT(opline, opline->op1); + /* ZEND_CLONE also exists as the clone() function and both implementations must be kept in sync. */ + do { if (IS_CONST == IS_CONST || (IS_CONST != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { @@ -5196,7 +5198,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_ HANDLE_EXCEPTION(); } } - zend_throw_error(NULL, "__clone method called on non-object"); + zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj)); HANDLE_EXCEPTION(); } @@ -15428,6 +15430,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND SAVE_OPLINE(); obj = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); + /* ZEND_CLONE also exists as the clone() function and both implementations must be kept in sync. */ + do { if ((IS_TMP_VAR|IS_VAR) == IS_CONST || ((IS_TMP_VAR|IS_VAR) != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { @@ -15444,7 +15448,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND HANDLE_EXCEPTION(); } } - zend_throw_error(NULL, "__clone method called on non-object"); + zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); HANDLE_EXCEPTION(); } @@ -33523,6 +33527,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND SAVE_OPLINE(); obj = &EX(This); + /* ZEND_CLONE also exists as the clone() function and both implementations must be kept in sync. */ + do { if (IS_UNUSED == IS_CONST || (IS_UNUSED != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { @@ -33539,7 +33545,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND HANDLE_EXCEPTION(); } } - zend_throw_error(NULL, "__clone method called on non-object"); + zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj)); HANDLE_EXCEPTION(); } @@ -41042,6 +41048,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPC SAVE_OPLINE(); obj = EX_VAR(opline->op1.var); + /* ZEND_CLONE also exists as the clone() function and both implementations must be kept in sync. */ + do { if (IS_CV == IS_CONST || (IS_CV != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { @@ -41058,7 +41066,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPC HANDLE_EXCEPTION(); } } - zend_throw_error(NULL, "__clone method called on non-object"); + zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj)); HANDLE_EXCEPTION(); } diff --git a/build/gen_stub.php b/build/gen_stub.php index fcef8213d0b55..d9327b67d042f 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -1009,6 +1009,9 @@ class FunctionName implements FunctionOrMethodName { private /* readonly */ Name $name; public function __construct(Name $name) { + if ($name->name === '_clone') { + $name = new Name('clone', $name->getAttributes()); + } $this->name = $name; } @@ -3049,6 +3052,7 @@ class PropertyInfo extends VariableLike "parent" => "ZEND_STR_PARENT", "username" => "ZEND_STR_USERNAME", "password" => "ZEND_STR_PASSWORD", + "clone" => "ZEND_STR_CLONE", ]; /** diff --git a/ext/opcache/tests/func_info.phpt b/ext/opcache/tests/func_info.phpt index 8b1f9ef436c4b..9596aa23199d2 100644 --- a/ext/opcache/tests/func_info.phpt +++ b/ext/opcache/tests/func_info.phpt @@ -16,7 +16,7 @@ foreach (get_defined_functions()["internal"] as $function) { if (in_array($function, ["extract", "compact", "get_defined_vars"])) { continue; } - $contents .= " \$result = {$function}();\n"; + $contents .= " \$result = \\{$function}();\n"; } $contents .= "}\n";