@@ -2589,6 +2589,39 @@ static uint32_t prop_assign_op_result_type(uint32_t tmp, const zend_property_inf
25892589 return (tmp & prop_type ) | scalar_coercion_type (tmp & ~prop_type & MAY_BE_ANY , prop_type , strict );
25902590}
25912591
2592+ /* Whether ASSIGN_OBJ_OP may return the uncoerced result by having overloaded handler. */
2593+ static bool assign_obj_op_may_be_overloaded (const zend_op_array * op_array , const zend_ssa * ssa , const zend_op * opline , const zend_ssa_op * ssa_op , const zend_property_info * prop_info )
2594+ {
2595+ const zend_class_entry * ce ;
2596+ bool is_instanceof ;
2597+
2598+ if (!prop_info ) {
2599+ return true;
2600+ }
2601+
2602+ if (opline -> op1_type == IS_UNUSED ) {
2603+ ce = op_array -> scope ;
2604+ is_instanceof = true;
2605+ } else if (ssa_op -> op1_use >= 0 ) {
2606+ ce = ssa -> var_info [ssa_op -> op1_use ].ce ;
2607+ is_instanceof = ssa -> var_info [ssa_op -> op1_use ].is_instanceof ;
2608+ } else {
2609+ return true;
2610+ }
2611+
2612+ /* A child class may add __get() or hooks. */
2613+ if (!ce
2614+ || (is_instanceof && !(ce -> ce_flags & ZEND_ACC_FINAL ))
2615+ || !(ce -> ce_flags & ZEND_ACC_LINKED )) {
2616+ return true;
2617+ }
2618+
2619+ return ce -> __get /* Unset property */
2620+ || ce -> create_object /* Custom handlers */
2621+ || prop_info -> hooks
2622+ || (prop_info -> flags & ZEND_ACC_READONLY ); /* Reinitialized in __clone() */
2623+ }
2624+
25922625static bool result_may_be_separated (zend_ssa * ssa , zend_ssa_op * ssa_op )
25932626{
25942627 int tmp_var = ssa_op -> result_def ;
@@ -2908,9 +2941,15 @@ static zend_always_inline zend_result _zend_update_type_info(
29082941 }
29092942 } else if (opline -> opcode == ZEND_ASSIGN_OBJ_OP
29102943 || opline -> opcode == ZEND_ASSIGN_STATIC_PROP_OP ) {
2911- /* The return value must also satisfy the property type */
2944+ /* The return value must also satisfy the property type,
2945+ * unless the overloaded handlers return the uncoerced result. */
29122946 t1 = zend_fetch_prop_type (script , prop_info , & ce );
2913- tmp = prop_assign_op_result_type (tmp , prop_info , t1 , (op_array -> fn_flags & ZEND_ACC_STRICT_TYPES ) != 0 );
2947+ if (opline -> opcode == ZEND_ASSIGN_OBJ_OP
2948+ && assign_obj_op_may_be_overloaded (op_array , ssa , opline , ssa_op , prop_info )) {
2949+ tmp |= prop_assign_op_result_type (tmp , prop_info , t1 , (op_array -> fn_flags & ZEND_ACC_STRICT_TYPES ) != 0 );
2950+ } else {
2951+ tmp = prop_assign_op_result_type (tmp , prop_info , t1 , (op_array -> fn_flags & ZEND_ACC_STRICT_TYPES ) != 0 );
2952+ }
29142953 } else {
29152954 if (tmp & MAY_BE_REF ) {
29162955 /* Typed reference may cause auto conversion */
0 commit comments