mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
RFC: Turn clone() into a function (#18919)
RFC: https://wiki.php.net/rfc/clone_with_v2 Co-authored-by: Volker Dusch <volker@tideways-gmbh.com>
This commit is contained in:
1
NEWS
1
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}))
|
||||
|
||||
31
Zend/tests/clone/ast.phpt
Normal file
31
Zend/tests/clone/ast.phpt
Normal file
@@ -0,0 +1,31 @@
|
||||
--TEST--
|
||||
Ast Printing
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$x = new stdClass();
|
||||
|
||||
|
||||
try {
|
||||
assert(false && $y = clone $x);
|
||||
} catch (Error $e) {
|
||||
echo $e->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(...)))
|
||||
@@ -4,11 +4,11 @@ Bug #36071 (Engine Crash related with 'clone')
|
||||
error_reporting=4095
|
||||
--FILE--
|
||||
<?php
|
||||
$a = clone 0;
|
||||
$a[0]->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
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
Bug #42817 (clone() on a non-object does not result in a fatal error)
|
||||
--FILE--
|
||||
<?php
|
||||
$a = clone(null);
|
||||
array_push($a->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
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
Bug #42818 ($foo = clone(array()); leaks memory)
|
||||
--FILE--
|
||||
<?php
|
||||
$foo = clone(array());
|
||||
try {
|
||||
$foo = clone(array());
|
||||
} catch (Error $e) {
|
||||
echo $e::class, ": ", $e->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
|
||||
|
||||
@@ -3,11 +3,12 @@ Using clone statement on non-object
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = clone array();
|
||||
try {
|
||||
$a = clone array();
|
||||
} catch (Error $e) {
|
||||
echo $e::class, ": ", $e->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
|
||||
|
||||
@@ -3,13 +3,13 @@ Using clone statement on undefined variable
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = clone $b;
|
||||
try {
|
||||
$a = clone $b;
|
||||
} catch (Error $e) {
|
||||
echo $e::class, ": ", $e->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
|
||||
|
||||
55
Zend/tests/clone/clone_005.phpt
Normal file
55
Zend/tests/clone/clone_005.phpt
Normal file
@@ -0,0 +1,55 @@
|
||||
--TEST--
|
||||
Clone as a function.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$x = new stdClass();
|
||||
|
||||
\var_dump(\clone($x));
|
||||
\var_dump(\array_map('clone', [$x, $x, $x]));
|
||||
\var_dump(\array_map(clone(...), [$x, $x, $x]));
|
||||
|
||||
class Foo {
|
||||
private function __clone() {
|
||||
|
||||
}
|
||||
|
||||
public function clone_me() {
|
||||
// Verify visibility when going through array_map().
|
||||
return array_map(\clone(...), [$this]);
|
||||
}
|
||||
}
|
||||
|
||||
$f = new Foo();
|
||||
|
||||
$clone = $f->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)
|
||||
@@ -23,6 +23,7 @@ function test_clone() {
|
||||
$b = clone $c->x;
|
||||
}
|
||||
|
||||
// No catch, because we want to test Exception::__toString().
|
||||
test_clone();
|
||||
?>
|
||||
--EXPECTF--
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2345,8 +2345,6 @@ simple_list:
|
||||
}
|
||||
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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -7,6 +7,9 @@ class stdClass
|
||||
{
|
||||
}
|
||||
|
||||
/** @refcount 1 */
|
||||
function _clone(object $object): object {}
|
||||
|
||||
function exit(string|int $status = 0): never {}
|
||||
|
||||
/** @alias exit */
|
||||
|
||||
8
Zend/zend_builtin_functions_arginfo.h
generated
8
Zend/zend_builtin_functions_arginfo.h
generated
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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") \
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
16
Zend/zend_vm_execute.h
generated
16
Zend/zend_vm_execute.h
generated
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user