1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Implement GH-18261: Allow cast to be used in constant expressions (#18264)

This commit is contained in:
Niels Dossche
2025-04-11 17:53:43 +02:00
committed by GitHub
parent e11a47f18b
commit 2f6c069296
9 changed files with 182 additions and 230 deletions

1
NEWS
View File

@@ -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)

View File

@@ -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

View File

@@ -0,0 +1,64 @@
--TEST--
Constant expressions with cast
--FILE--
<?php
class X {
public int $foo = 3;
}
const T1 = (int) 0.3;
const T2 = (bool) 0.3;
const T3 = (string) [];
const T4 = (object) ["a" => 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) "<required>"
["$values"]=>
string(10) "<optional>"
}
}
}
array(1) {
["foo"]=>
int(3)
}
array(3) {
["date"]=>
string(%d) "%s"
["timezone_type"]=>
int(%d)
["timezone"]=>
string(%d) "%s"
}
int(1)

View File

@@ -0,0 +1,10 @@
--TEST--
Constant expressions with object cast in property
--FILE--
<?php
class X {
public $foo = (object) [];
}
?>
--EXPECTF--
Fatal error: Object casts are not supported in this context in %s on line %d

View File

@@ -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;

View File

@@ -11121,6 +11121,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
@@ -11395,6 +11396,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,

View File

@@ -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);

View File

@@ -6459,7 +6459,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);
@@ -6493,53 +6492,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);
}
}

192
Zend/zend_vm_execute.h generated
View File

@@ -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);
}
}
@@ -20154,7 +20110,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);
@@ -20187,53 +20142,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);
}
}
@@ -22820,7 +22732,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);
@@ -22854,53 +22765,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);
}
}
@@ -41061,7 +40929,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);
@@ -41094,53 +40961,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);
}
}