<? php $a =1; $b =&A;
$c = 2;
$d = $c; $c = $b;
Conclusion:
Holds a pointer to the left value, prepares for memory reclamation, and the pointer is again assigned a value
1) The left value is not a reference
1.1) If the Lvalue refcount_gc is 1, indicating that the left value is assigned a value,
1.1.1) Rvalue is a reference, enter the 2nd step
1.1.2) The right value is not a reference, REFCOUNT_GC plus 1, copy the right value to the left value
1.2) If it is not 1, the description first appears, or is used by other variables together Zval, its refcount_gc minus 1, will be left-valued GC buffer (the GC determines whether the need to free memory)
1.2.1) Rvalue is a reference , allocating memory to an lvalue, copying an rvalue value to an lvalue, and value.str.val a deep copy of the right value, refcount_gc setting 1
1.2.2) Rvalue is not a reference, copy the right value directly to the left value, REFCOUNT_GC plus 1
2) The lvalue is a reference, indicating that the left value is assigned a value, the lvalue uses the destructor, reclaims the memory, copies the Vaue of the right value to the left value, and deep copies the value.str.val of the right value.
<? PHP $a=1; $b=&$a; $c=2; $b=$c;
Static intzend_fastcall Zend_assign_spec_cv_cv_handler (Zend_opcode_handler_args) {use_opline zval*value; Zval**variable_ptr_ptr; Save_opline (); Value= _get_zval_ptr_cv_bp_var_r (Ex_cvs (), Opline->op2.vartsrmls_cc); Variable_ptr_ptr= _get_zval_ptr_ptr_cv_bp_var_w (Ex_cvs (), Opline->op1.vartsrmls_cc); if(IS_CV = = Is_var && unexpected (variable_ptr_ptr = =NULL)) { if(Zend_assign_to_string_offset (&ex_t (OPLINE->OP1.var), value, IS_CV tsrmls_cc)) {if(return_value_used (opline)) {Zval*retval; Alloc_zval (retval); Zval_stringl (retval, Z_strval_p (ex_t (Opline->op1.var). Str_offset.str) +ex_t (OPLINE->OP1.var). Str_offset.offset,1,1); Init_pzval (retval); Ai_set_ptr (&ex_t (Opline->result.var), retval); } } Else if(return_value_used (opline)) {Pzval_lock (&EG (uninitialized_zval)); Ai_set_ptr (&ex_t (Opline->result.var), &EG (uninitialized_zval)); } } Else if(IS_CV = = Is_var && unexpected (*variable_ptr_ptr = = &EG (error_zval))) { if(0) {zval_dtor (value); } if(return_value_used (opline)) {Pzval_lock (&EG (uninitialized_zval)); Ai_set_ptr (&ex_t (Opline->result.var), &EG (uninitialized_zval)); } } Else { if(IS_CV = =Is_tmp_var) {Value=zend_assign_tmp_to_variable (variable_ptr_ptr, value tsrmls_cc); } Else if(IS_CV = =is_const) {Value=zend_assign_const_to_variable (variable_ptr_ptr, value tsrmls_cc); } Else{Value=zend_assign_to_variable (variable_ptr_ptr, value tsrmls_cc); } if(return_value_used (opline)) {Pzval_lock (VALUE); Ai_set_ptr (&ex_t (Opline->result.var), value); } } /*zend_assign_to_variable () always takes care of OP2, never free it!*/check_exception (); Zend_vm_next_opcode ();}
StaticInline zval* zend_assign_to_variable (zval **variable_ptr_ptr, Zval *value TSRMLS_DC) {Zval*variable_ptr = *variable_ptr_ptr; Zval Garbage; if(Z_type_p (variable_ptr) = = Is_object &&Unexpected (z_obj_handler_p (Variable_ptr,Set) !=NULL)) {z_obj_handler_p (variable_ptr,Set) (variable_ptr_ptr, value tsrmls_cc); returnvariable_ptr; } if(Expected (!pzval_is_ref (variable_ptr))) { if(Z_refcount_p (variable_ptr) = =1) { if(Unexpected (variable_ptr = =value)) { returnvariable_ptr; } Else if(Expected (!Pzval_is_ref (value))) {z_addref_p (value); *variable_ptr_ptr =value; if(Expected (Variable_ptr! = &EG (uninitialized_zval))) {Gc_remove_zval_from_buffer (variable_ptr); Zval_dtor (VARIABLE_PTR); Efree (VARIABLE_PTR); } Else{z_delref_p (variable_ptr); } returnvalue; } Else { GotoCopy_value; } } Else{/*we need to split*/z_delref_p (VARIABLE_PTR); Gc_zval_check_possible_root (VARIABLE_PTR); if(Pzval_is_ref (value) && z_refcount_p (value) >0) {alloc_zval (variable_ptr); *variable_ptr_ptr =variable_ptr; Init_pzval_copy (variable_ptr, value); Zval_copy_ctor (VARIABLE_PTR); returnvariable_ptr; } Else { *variable_ptr_ptr =value; z_addref_p (value); z_unset_isref_p (value); returnvalue; } } } Else { if(Expected (Variable_ptr! =value)) {copy_value:if(Expected (Z_type_p (VARIABLE_PTR) <=Is_bool)) { /*Nothing to destroy*/Zval_copy_value (variable_ptr, VALUE); Zendi_zval_copy_ctor (*variable_ptr); } Else{Zval_copy_value (&garbage, Variable_ptr); Zval_copy_value (Variable_ptr, VALUE); Zendi_zval_copy_ctor (*variable_ptr); _zval_dtor_func (&garbage zend_file_line_cc); } } returnvariable_ptr; }}
// zend.h #define Init_pzval_copy (z, v) do { zval_copy_value (z, v); 1 ); Z_unset_isref_p (z); while (0)
Static Zend_always_inline Zend_bool zval_unset_isref_p (zval* pz) {
return pz->is_ref__gc = 0;
}