diff --git a/Zend/tests/assign_coalesce_008.phpt b/Zend/tests/assign_coalesce_008.phpt new file mode 100644 index 000000000000..ae027da58efe --- /dev/null +++ b/Zend/tests/assign_coalesce_008.phpt @@ -0,0 +1,64 @@ +--TEST-- +Assign coalesce: All calls should be memoized +--FILE-- +foo()->foo()->{$foo->bar()} ??= 42; +var_dump($foo); +$foo->foo()->baz ??= 42; + +?> +--EXPECT-- +bar +foo +array(1) { + ["bar"]=> + int(42) +} +Foo::foo +Foo::foo +Foo::bar +object(Foo)#1 (1) { + ["prop"]=> + int(42) +} +Foo::foo +Foo::__isset +Foo::__set +int(42) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 69ba712576ce..8fb56ff9558e 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4587,14 +4587,7 @@ static void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{ if (runtime_resolution) { if (zend_string_equals_literal_ci(zend_ast_get_str(name_ast), "assert") && !is_callable_convert) { - if (CG(memoize_mode) == ZEND_MEMOIZE_NONE) { - zend_compile_assert(result, zend_ast_get_list(args_ast), Z_STR(name_node.u.constant), NULL, ast->lineno); - } else { - /* We want to always memoize assert calls, even if they are positioned in - * write-context. This prevents memoizing their arguments that might not be - * evaluated if assertions are disabled, using a TMPVAR that wasn't initialized. */ - zend_compile_memoized_expr(result, ast); - } + zend_compile_assert(result, zend_ast_get_list(args_ast), Z_STR(name_node.u.constant), NULL, ast->lineno); } else { zend_compile_ns_call(result, &name_node, args_ast, ast->lineno); } @@ -4613,14 +4606,7 @@ static void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{ /* Special assert() handling should apply independently of compiler flags. */ if (fbc && zend_string_equals_literal(lcname, "assert") && !is_callable_convert) { - if (CG(memoize_mode) == ZEND_MEMOIZE_NONE) { - zend_compile_assert(result, zend_ast_get_list(args_ast), lcname, fbc, ast->lineno); - } else { - /* We want to always memoize assert calls, even if they are positioned in - * write-context. This prevents memoizing their arguments that might not be - * evaluated if assertions are disabled, using a TMPVAR that wasn't initialized. */ - zend_compile_memoized_expr(result, ast); - } + zend_compile_assert(result, zend_ast_get_list(args_ast), lcname, fbc, ast->lineno); zend_string_release(lcname); zval_ptr_dtor(&name_node.u.constant); return; @@ -10589,6 +10575,17 @@ static zend_op *zend_compile_var_inner(znode *result, zend_ast *ast, uint32_t ty { CG(zend_lineno) = zend_ast_get_lineno(ast); + if (CG(memoize_mode) != ZEND_MEMOIZE_NONE) { + switch (ast->kind) { + case ZEND_AST_CALL: + case ZEND_AST_METHOD_CALL: + case ZEND_AST_NULLSAFE_METHOD_CALL: + case ZEND_AST_STATIC_CALL: + zend_compile_memoized_expr(result, ast); + return &CG(active_op_array)->opcodes[CG(active_op_array)->last - 1]; + } + } + switch (ast->kind) { case ZEND_AST_VAR: return zend_compile_simple_var(result, ast, type, 0);