diff --git a/NEWS b/NEWS index 65cebd217e130..4872d1294c677 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,7 @@ PHP NEWS (timwolla, Volker Dusch) . Added get_error_handler(), get_exception_handler() functions. (Arnaud) . Fixed bug GH-15753 and GH-16198 (Bind traits before parent class). (ilutov) + . Added support for casts in constant expressions. (nielsdos) - Curl: . Added curl_multi_get_handles(). (timwolla) diff --git a/UPGRADING b/UPGRADING index 26ed02c9af9a0..c7d0dc0e80c4b 100644 --- a/UPGRADING +++ b/UPGRADING @@ -130,6 +130,7 @@ PHP 8.5 UPGRADE NOTES RFC: https://wiki.php.net/rfc/marking_return_value_as_important . Added asymmetric visibility support for static properties. RFC: https://wiki.php.net/rfc/static-aviz + . Added support for casts in constant expressions. - Curl: . Added support for share handles that are persisted across multiple PHP diff --git a/Zend/tests/constexpr/constant_expressions_cast.phpt b/Zend/tests/constexpr/constant_expressions_cast.phpt new file mode 100644 index 0000000000000..4431e2c08d6b0 --- /dev/null +++ b/Zend/tests/constexpr/constant_expressions_cast.phpt @@ -0,0 +1,64 @@ +--TEST-- +Constant expressions with cast +--FILE-- + 1]; +const T5 = (float) 5; +const T6 = (array) ""; +const T7 = (array) var_dump(...); +const T8 = (array) new X; +const T9 = (array) new DateTime; +const T10 = (int) new DateTime; + +var_dump(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); +?> +--EXPECTF-- +Warning: Array to string conversion in %s on line %d + +Warning: Object of class DateTime could not be converted to int in %s on line %d +int(0) +bool(true) +string(5) "Array" +object(stdClass)#%d (1) { + ["a"]=> + int(1) +} +float(5) +array(1) { + [0]=> + string(0) "" +} +array(1) { + [0]=> + object(Closure)#%d (2) { + ["function"]=> + string(8) "var_dump" + ["parameter"]=> + array(2) { + ["$value"]=> + string(10) "" + ["$values"]=> + string(10) "" + } + } +} +array(1) { + ["foo"]=> + int(3) +} +array(3) { + ["date"]=> + string(%d) "%s" + ["timezone_type"]=> + int(%d) + ["timezone"]=> + string(%d) "%s" +} +int(1) diff --git a/Zend/tests/constexpr/constant_expressions_cast_object_property.phpt b/Zend/tests/constexpr/constant_expressions_cast_object_property.phpt new file mode 100644 index 0000000000000..63616f0f8bf3b --- /dev/null +++ b/Zend/tests/constexpr/constant_expressions_cast_object_property.phpt @@ -0,0 +1,10 @@ +--TEST-- +Constant expressions with object cast in property +--FILE-- + +--EXPECTF-- +Fatal error: Object casts are not supported in this context in %s on line %d diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 2551f876d4465..991d85ff39ce1 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -702,6 +702,41 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner( } zval_ptr_dtor_nogc(&op1); break; + case ZEND_AST_CAST: + if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) { + ret = FAILURE; + break; + } + if (ast->attr == Z_TYPE(op1)) { + ZVAL_COPY_VALUE(result, &op1); + } else { + switch (ast->attr) { + case _IS_BOOL: + ZVAL_BOOL(result, zend_is_true(&op1)); + break; + case IS_LONG: + ZVAL_LONG(result, zval_get_long_func(&op1, false)); + break; + case IS_DOUBLE: + ZVAL_DOUBLE(result, zval_get_double_func(&op1)); + break; + case IS_STRING: + ZVAL_STR(result, zval_get_string_func(&op1)); + break; + case IS_ARRAY: + zend_cast_zval_to_array(result, &op1, IS_VAR); + break; + case IS_OBJECT: + zend_cast_zval_to_object(result, &op1, IS_VAR); + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + zval_ptr_dtor_nogc(&op1); + if (UNEXPECTED(EG(exception))) { + ret = FAILURE; + } + } + break; case ZEND_AST_OR: if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) { ret = FAILURE; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2e405de30ea62..a82af1580c9a7 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -11156,6 +11156,7 @@ static bool zend_is_allowed_in_const_expr(zend_ast_kind kind) /* {{{ */ || kind == ZEND_AST_AND || kind == ZEND_AST_OR || kind == ZEND_AST_UNARY_OP || kind == ZEND_AST_UNARY_PLUS || kind == ZEND_AST_UNARY_MINUS + || kind == ZEND_AST_CAST || kind == ZEND_AST_CONDITIONAL || kind == ZEND_AST_DIM || kind == ZEND_AST_ARRAY || kind == ZEND_AST_ARRAY_ELEM || kind == ZEND_AST_UNPACK @@ -11430,6 +11431,12 @@ static void zend_compile_const_expr(zend_ast **ast_ptr, void *context) /* {{{ */ case ZEND_AST_MAGIC_CONST: zend_compile_const_expr_magic_const(ast_ptr); break; + case ZEND_AST_CAST: + if (ast->attr == IS_OBJECT && !ctx->allow_dynamic) { + zend_error_noreturn(E_COMPILE_ERROR, + "Object casts are not supported in this context"); + } + break; case ZEND_AST_NEW: if (!ctx->allow_dynamic) { zend_error_noreturn(E_COMPILE_ERROR, diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index e96a217a2904f..7f9b41e465502 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -219,6 +219,60 @@ static zend_always_inline void zend_safe_assign_to_variable_noref(zval *variable } } +static zend_always_inline void zend_cast_zval_to_object(zval *result, zval *expr, uint8_t op1_type) { + HashTable *ht; + + ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); + if (Z_TYPE_P(expr) == IS_ARRAY) { + ht = zend_symtable_to_proptable(Z_ARR_P(expr)); + if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { + /* TODO: try not to duplicate immutable arrays as well ??? */ + ht = zend_array_dup(ht); + } + Z_OBJ_P(result)->properties = ht; + } else if (Z_TYPE_P(expr) != IS_NULL) { + Z_OBJ_P(result)->properties = ht = zend_new_array(1); + expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); + if (op1_type == IS_CONST) { + if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); + } else { + if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); + } + } +} + +static zend_always_inline void zend_cast_zval_to_array(zval *result, zval *expr, uint8_t op1_type) { + extern zend_class_entry *zend_ce_closure; + if (op1_type == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { + if (Z_TYPE_P(expr) != IS_NULL) { + ZVAL_ARR(result, zend_new_array(1)); + expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); + if (op1_type == IS_CONST) { + if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); + } else { + if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); + } + } else { + ZVAL_EMPTY_ARRAY(result); + } + } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { + /* Optimized version without rebuilding properties HashTable */ + ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); + } else { + HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); + if (obj_ht) { + /* fast copy */ + ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, + (Z_OBJCE_P(expr)->default_properties_count || + Z_OBJ_P(expr)->handlers != &std_object_handlers || + GC_IS_RECURSIVE(obj_ht)))); + zend_release_properties(obj_ht); + } else { + ZVAL_EMPTY_ARRAY(result); + } + } +} + ZEND_API zend_result ZEND_FASTCALL zval_update_constant(zval *pp); ZEND_API zend_result ZEND_FASTCALL zval_update_constant_ex(zval *pp, zend_class_entry *scope); ZEND_API zend_result ZEND_FASTCALL zval_update_constant_with_ctx(zval *pp, zend_class_entry *scope, zend_ast_evaluate_ctx *ctx); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 162b7e84cefbe..3e1eead81706c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6460,7 +6460,6 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) USE_OPLINE zval *expr; zval *result = EX_VAR(opline->result.var); - HashTable *ht; SAVE_OPLINE(); expr = GET_OP1_ZVAL_PTR(BP_VAR_R); @@ -6494,53 +6493,10 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) } if (opline->extended_value == IS_ARRAY) { - if (OP1_TYPE == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { - if (Z_TYPE_P(expr) != IS_NULL) { - ZVAL_ARR(result, zend_new_array(1)); - expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); - if (OP1_TYPE == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } else { - ZVAL_EMPTY_ARRAY(result); - } - } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { - /* Optimized version without rebuilding properties HashTable */ - ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); - } else { - HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); - if (obj_ht) { - /* fast copy */ - ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(expr)->default_properties_count || - Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht)))); - zend_release_properties(obj_ht); - } else { - ZVAL_EMPTY_ARRAY(result); - } - } + zend_cast_zval_to_array(result, expr, OP1_TYPE); } else { ZEND_ASSERT(opline->extended_value == IS_OBJECT); - ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); - if (Z_TYPE_P(expr) == IS_ARRAY) { - ht = zend_symtable_to_proptable(Z_ARR_P(expr)); - if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { - /* TODO: try not to duplicate immutable arrays as well ??? */ - ht = zend_array_dup(ht); - } - Z_OBJ_P(result)->properties = ht; - } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); - expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); - if (OP1_TYPE == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } + zend_cast_zval_to_object(result, expr, OP1_TYPE); } } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 902e254ff2424..26f423cdbe011 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5233,7 +5233,6 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H USE_OPLINE zval *expr; zval *result = EX_VAR(opline->result.var); - HashTable *ht; SAVE_OPLINE(); expr = RT_CONSTANT(opline, opline->op1); @@ -5266,53 +5265,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H } if (opline->extended_value == IS_ARRAY) { - if (IS_CONST == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { - if (Z_TYPE_P(expr) != IS_NULL) { - ZVAL_ARR(result, zend_new_array(1)); - expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); - if (IS_CONST == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } else { - ZVAL_EMPTY_ARRAY(result); - } - } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { - /* Optimized version without rebuilding properties HashTable */ - ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); - } else { - HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); - if (obj_ht) { - /* fast copy */ - ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(expr)->default_properties_count || - Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht)))); - zend_release_properties(obj_ht); - } else { - ZVAL_EMPTY_ARRAY(result); - } - } + zend_cast_zval_to_array(result, expr, IS_CONST); } else { ZEND_ASSERT(opline->extended_value == IS_OBJECT); - ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); - if (Z_TYPE_P(expr) == IS_ARRAY) { - ht = zend_symtable_to_proptable(Z_ARR_P(expr)); - if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { - /* TODO: try not to duplicate immutable arrays as well ??? */ - ht = zend_array_dup(ht); - } - Z_OBJ_P(result)->properties = ht; - } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); - expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); - if (IS_CONST == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } + zend_cast_zval_to_object(result, expr, IS_CONST); } } @@ -20155,7 +20111,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC USE_OPLINE zval *expr; zval *result = EX_VAR(opline->result.var); - HashTable *ht; SAVE_OPLINE(); expr = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); @@ -20188,53 +20143,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC } if (opline->extended_value == IS_ARRAY) { - if (IS_TMP_VAR == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { - if (Z_TYPE_P(expr) != IS_NULL) { - ZVAL_ARR(result, zend_new_array(1)); - expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); - if (IS_TMP_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } else { - ZVAL_EMPTY_ARRAY(result); - } - } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { - /* Optimized version without rebuilding properties HashTable */ - ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); - } else { - HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); - if (obj_ht) { - /* fast copy */ - ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(expr)->default_properties_count || - Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht)))); - zend_release_properties(obj_ht); - } else { - ZVAL_EMPTY_ARRAY(result); - } - } + zend_cast_zval_to_array(result, expr, IS_TMP_VAR); } else { ZEND_ASSERT(opline->extended_value == IS_OBJECT); - ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); - if (Z_TYPE_P(expr) == IS_ARRAY) { - ht = zend_symtable_to_proptable(Z_ARR_P(expr)); - if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { - /* TODO: try not to duplicate immutable arrays as well ??? */ - ht = zend_array_dup(ht); - } - Z_OBJ_P(result)->properties = ht; - } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); - expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); - if (IS_TMP_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } + zend_cast_zval_to_object(result, expr, IS_TMP_VAR); } } @@ -22822,7 +22734,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC USE_OPLINE zval *expr; zval *result = EX_VAR(opline->result.var); - HashTable *ht; SAVE_OPLINE(); expr = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -22856,53 +22767,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC } if (opline->extended_value == IS_ARRAY) { - if (IS_VAR == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { - if (Z_TYPE_P(expr) != IS_NULL) { - ZVAL_ARR(result, zend_new_array(1)); - expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); - if (IS_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } else { - ZVAL_EMPTY_ARRAY(result); - } - } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { - /* Optimized version without rebuilding properties HashTable */ - ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); - } else { - HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); - if (obj_ht) { - /* fast copy */ - ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(expr)->default_properties_count || - Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht)))); - zend_release_properties(obj_ht); - } else { - ZVAL_EMPTY_ARRAY(result); - } - } + zend_cast_zval_to_array(result, expr, IS_VAR); } else { ZEND_ASSERT(opline->extended_value == IS_OBJECT); - ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); - if (Z_TYPE_P(expr) == IS_ARRAY) { - ht = zend_symtable_to_proptable(Z_ARR_P(expr)); - if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { - /* TODO: try not to duplicate immutable arrays as well ??? */ - ht = zend_array_dup(ht); - } - Z_OBJ_P(result)->properties = ht; - } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); - expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); - if (IS_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } + zend_cast_zval_to_object(result, expr, IS_VAR); } } @@ -41065,7 +40933,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO USE_OPLINE zval *expr; zval *result = EX_VAR(opline->result.var); - HashTable *ht; SAVE_OPLINE(); expr = _get_zval_ptr_cv_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); @@ -41098,53 +40965,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO } if (opline->extended_value == IS_ARRAY) { - if (IS_CV == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { - if (Z_TYPE_P(expr) != IS_NULL) { - ZVAL_ARR(result, zend_new_array(1)); - expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); - if (IS_CV == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } else { - ZVAL_EMPTY_ARRAY(result); - } - } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { - /* Optimized version without rebuilding properties HashTable */ - ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); - } else { - HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); - if (obj_ht) { - /* fast copy */ - ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(expr)->default_properties_count || - Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht)))); - zend_release_properties(obj_ht); - } else { - ZVAL_EMPTY_ARRAY(result); - } - } + zend_cast_zval_to_array(result, expr, IS_CV); } else { ZEND_ASSERT(opline->extended_value == IS_OBJECT); - ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); - if (Z_TYPE_P(expr) == IS_ARRAY) { - ht = zend_symtable_to_proptable(Z_ARR_P(expr)); - if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { - /* TODO: try not to duplicate immutable arrays as well ??? */ - ht = zend_array_dup(ht); - } - Z_OBJ_P(result)->properties = ht; - } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); - expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); - if (IS_CV == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } + zend_cast_zval_to_object(result, expr, IS_CV); } }