Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 8.1k
RFC: Turn clone() into a function#18919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
212f92371df8dd24c0ce7c043b5ee1729f8573cd165457a23f3462cc8b25a9b0acfc73e2bd32c6ee0ef14977ef669bedf8File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(...))) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
TimWolla marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| cloned = zobj->handlers->clone_obj(zobj); | ||
| ZEND_ASSERT(cloned || EG(exception)); | ||
| if (EXPECTED(cloned)) { | ||
| RETURN_OBJ(cloned); | ||
| } | ||
| } | ||
| ZEND_FUNCTION(exit) | ||
| { | ||
| zend_string *str = NULL; | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) { | ||
TimWolla marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| 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; | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.