1. <?php
  2. $a=1;
  3. $b=&$a;
  4. $c=2;
  5. $a=&$c;
  6. echo $a."\n";
  7. echo $b;
  8. 2
  9. 1

结论:

首先保存 左值的内存地址, 因这个内存地址会被再次被赋值

1)右值是引用

  进入2.2 2.3 2.4步骤

  例子:

  1. <?php
  2.   $a=1;
      $c=2;
  3.   $b=&$a; //执行到这里时,属于第2种情况
  4.   $c=&$a; //执行到这里时,属于第1种情况,

2)右值不是引用,右值的refcount_gc减1

  2.1)如果refcount_gc减1,大于0 ,说明有别的变量也共同使用了zval,需要单独分配内存给右值

  2.2)将右值(内存地址)赋值给左值

  2.3)refcount_gc 加1,并设置 is_ref=1 

  2.4)销毁左值

    2.3.1)将上面保存的左值的zval的refcount_gc减1

      2.3.1.1)上面值为0,则zval_dtor

      2.3.1.2)上面值大于0,则进入GC buffer, 但zval类型必须为 object或 array

  

可以发现$a,$b,$c全是CV变量

当php解释器执行到$b=&$a时,会执行到下面的handler

  1. static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
  2. {
  3. USE_OPLINE
  4. zend_free_op free_op2;
  5. zval **variable_ptr_ptr;
  6. zval **value_ptr_ptr;
  7.  
  8. SAVE_OPLINE();
  9. value_ptr_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op2.var TSRMLS_CC);
  10.  
  11. if (IS_CV == IS_VAR &&
  12. value_ptr_ptr &&
  13. !Z_ISREF_PP(value_ptr_ptr) &&
  14. opline->extended_value == ZEND_RETURNS_FUNCTION &&
  15. !EX_T(opline->op2.var).var.fcall_returned_reference) {
  16. if (free_op2.var == NULL) {
  17. PZVAL_LOCK(*value_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */
  18. }
  19. zend_error(E_STRICT, "Only variables should be assigned by reference");
  20. if (UNEXPECTED(EG(exception) != NULL)) {
  21.  
  22. HANDLE_EXCEPTION();
  23. }
  24. return ZEND_ASSIGN_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
  25. } else if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) {
  26. PZVAL_LOCK(*value_ptr_ptr);
  27. }
  28. if (IS_CV == IS_VAR && UNEXPECTED(EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr)) {
  29. zend_error_noreturn(E_ERROR, "Cannot assign by reference to overloaded object");
  30. }
  31.  
  32. variable_ptr_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC);
  33. if ((IS_CV == IS_VAR && UNEXPECTED(value_ptr_ptr == NULL)) ||
  34. (IS_CV == IS_VAR && UNEXPECTED(variable_ptr_ptr == NULL))) {
  35. zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects");
  36. }
  37. zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); //在这里执行分配的操作
  38.  
  39. if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) {
  40. Z_DELREF_PP(variable_ptr_ptr);
  41. }
  42.  
  43. if (RETURN_VALUE_USED(opline)) {
  44. PZVAL_LOCK(*variable_ptr_ptr);
  45. AI_SET_PTR(&EX_T(opline->result.var), *variable_ptr_ptr);
  46. }
  47.  
  48. CHECK_EXCEPTION();
  49. ZEND_VM_NEXT_OPCODE();
  50. }
  1. static void zend_assign_to_variable_reference(zval **variable_ptr_ptr, zval **value_ptr_ptr TSRMLS_DC)
  2. {
  3. zval *variable_ptr = *variable_ptr_ptr;    
  4. zval *value_ptr = *value_ptr_ptr;       
  5.  
  6. if (variable_ptr == &EG(error_zval) || value_ptr == &EG(error_zval)) {
  7. variable_ptr_ptr = &EG(uninitialized_zval_ptr);
  8. } else if (variable_ptr != value_ptr) {
  9. if (!PZVAL_IS_REF(value_ptr)) { //此时右值不是一个引用
  10. /* break it away */
  11. Z_DELREF_P(value_ptr); //refcount_gc减1 的作用 是看 是否还有其他变量也使用了valu_ptr_ptr对应的zval,如果有,则重新分配zval
  12. if (Z_REFCOUNT_P(value_ptr)>) {
  13. ALLOC_ZVAL(*value_ptr_ptr);
  14. ZVAL_COPY_VALUE(*value_ptr_ptr, value_ptr);
  15. value_ptr = *value_ptr_ptr;
  16. zendi_zval_copy_ctor(*value_ptr);
  17. }
  18. Z_SET_REFCOUNT_P(value_ptr, ); //因为上面减1了,所以这里要加1,
  19. Z_SET_ISREF_P(value_ptr);//设置 is_ref为1
  20. }
  21.  
  22. *variable_ptr_ptr = value_ptr; //将variable_ptr_ptr这个地址指针内容 为 1 的地址
  23. Z_ADDREF_P(value_ptr); //还要将 refcount_gc加1
  24.  
  25. zval_ptr_dtor(&variable_ptr); //根据情况释放内存
  26. } else if (!Z_ISREF_P(variable_ptr)) {
  27. if (variable_ptr_ptr == value_ptr_ptr) {
  28. SEPARATE_ZVAL(variable_ptr_ptr);
  29. } else if (variable_ptr==&EG(uninitialized_zval)
  30. || Z_REFCOUNT_P(variable_ptr)>) {
  31. /* we need to separate */
  32. Z_SET_REFCOUNT_P(variable_ptr, Z_REFCOUNT_P(variable_ptr) - );
  33. ALLOC_ZVAL(*variable_ptr_ptr);
  34. ZVAL_COPY_VALUE(*variable_ptr_ptr, variable_ptr);
  35. zval_copy_ctor(*variable_ptr_ptr);
  36. *value_ptr_ptr = *variable_ptr_ptr;
  37. Z_SET_REFCOUNT_PP(variable_ptr_ptr, );
  38. }
  39. Z_SET_ISREF_PP(variable_ptr_ptr);
  40. }
  41. }
  1. //zend_variables.c
  2.  
  3. ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC)
  4. {
  5. switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
  6. case IS_RESOURCE: {
  7. TSRMLS_FETCH();
  8.  
  9. zend_list_addref(zvalue->value.lval);
  10. }
  11. break;
  12. case IS_BOOL:
  13. case IS_LONG:
  14. case IS_NULL:
  15. break;
  16. case IS_CONSTANT:
  17. case IS_STRING:
  18. CHECK_ZVAL_STRING_REL(zvalue);
  19. if (!IS_INTERNED(zvalue->value.str.val)) {
  20. zvalue->value.str.val = (char *) estrndup_rel(zvalue->value.str.val, zvalue->value.str.len);
  21. }
  22. break;
  23. case IS_ARRAY:
  24. case IS_CONSTANT_ARRAY: {
  25. zval *tmp;
  26. HashTable *original_ht = zvalue->value.ht;
  27. HashTable *tmp_ht = NULL;
  28. TSRMLS_FETCH();
  29.  
  30. if (zvalue->value.ht == &EG(symbol_table)) {
  31. return; /* do nothing */
  32. }
  33. ALLOC_HASHTABLE_REL(tmp_ht);
  34. zend_hash_init(tmp_ht, zend_hash_num_elements(original_ht), NULL, ZVAL_PTR_DTOR, );
  35. zend_hash_copy(tmp_ht, original_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
  36. zvalue->value.ht = tmp_ht;
  37. }
  38. break;
  39. case IS_OBJECT:
  40. {
  41. TSRMLS_FETCH();
  42. Z_OBJ_HT_P(zvalue)->add_ref(zvalue TSRMLS_CC);
  43. }
  44. break;
  45. }
  46. }
  1. //zend_API.h
  2.  
  3. #define CHECK_ZVAL_STRING_REL(z) \
  4. if (Z_STRVAL_P(z)[ Z_STRLEN_P(z) ] != '\0') { zend_error(E_WARNING, "String is not zero-terminated (%s) (source: %s:%d)", Z_STRVAL_P(z) ZEND_FILE_LINE_RELAY_CC); }
  1. //zend_alloc.h
  2.  
  3. #define estrndup_rel(s, length) _estrndup((s), (length) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC)
  1. //zend_alloc.c
  2.  
  3. ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  4. {
  5. char *p;
  6. #ifdef ZEND_SIGNALS
  7. TSRMLS_FETCH();
  8. #endif
  9.  
  10. HANDLE_BLOCK_INTERRUPTIONS();
  11.  
  12. p = (char *) _emalloc(length+ ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  13. if (UNEXPECTED(p == NULL)) {
  14. HANDLE_UNBLOCK_INTERRUPTIONS();
  15. return p;
  16. }
  17. memcpy(p, s, length);
  18. p[length] = ;
  19. HANDLE_UNBLOCK_INTERRUPTIONS();
  20. return p;
  21. }
  1. //zend_execute_API.c
    ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC) /* {{{ */
  2. {
  3. #if DEBUG_ZEND>=2
  4. printf("Reducing refcount for %x (%x): %d->%d\n", *zval_ptr, zval_ptr, Z_REFCOUNT_PP(zval_ptr), Z_REFCOUNT_PP(zval_ptr) - );
  5. #endif
  6. Z_DELREF_PP(zval_ptr);
  7. if (Z_REFCOUNT_PP(zval_ptr) == ) {
  8. TSRMLS_FETCH();
  9.  
  10. if (*zval_ptr != &EG(uninitialized_zval)) {
  11. GC_REMOVE_ZVAL_FROM_BUFFER(*zval_ptr);
  12. zval_dtor(*zval_ptr);
  13. efree_rel(*zval_ptr);
  14. }
  15. } else {
  16. TSRMLS_FETCH();
  17.  
  18. if (Z_REFCOUNT_PP(zval_ptr) == ) {
  19. Z_UNSET_ISREF_PP(zval_ptr);
  20. }
  21.  
  22. GC_ZVAL_CHECK_POSSIBLE_ROOT(*zval_ptr);
  23. }
  24. }
  1. //zend_variables.c
  2.  
  3. ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC)
  4. {
  5. switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
  6. case IS_STRING:
  7. case IS_CONSTANT:
  8. CHECK_ZVAL_STRING_REL(zvalue);
  9. STR_FREE_REL(zvalue->value.str.val);
  10. break;
  11. case IS_ARRAY:
  12. case IS_CONSTANT_ARRAY: {
  13. TSRMLS_FETCH();
  14.  
  15. if (zvalue->value.ht && (zvalue->value.ht != &EG(symbol_table))) {
  16. /* break possible cycles */
  17. Z_TYPE_P(zvalue) = IS_NULL;
  18. zend_hash_destroy(zvalue->value.ht);
  19. FREE_HASHTABLE(zvalue->value.ht);
  20. }
  21. }
  22. break;
  23. case IS_OBJECT:
  24. {
  25. TSRMLS_FETCH();
  26.  
  27. Z_OBJ_HT_P(zvalue)->del_ref(zvalue TSRMLS_CC);
  28. }
  29. break;
  30. case IS_RESOURCE:
  31. {
  32. TSRMLS_FETCH();
  33.  
  34. /* destroy resource */
  35. zend_list_delete(zvalue->value.lval);
  36. }
  37. break;
  38. case IS_LONG:
  39. case IS_DOUBLE:
  40. case IS_BOOL:
  41. case IS_NULL:
  42. default:
  43. return;
  44. break;
  45. }
  46. }
  1. //zend.h
  2.  
  3. #define STR_FREE_REL(ptr) if (ptr && !IS_INTERNED(ptr)) { efree_rel(ptr); }
  4.  
  5. #define efree_rel(ptr) _efree((ptr) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC)
  6.  
  7. //zend_alloc.c
  8.  
  9. ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  10. {
  11. TSRMLS_FETCH();
  12.  
  13. if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
  14. AG(mm_heap)->_free(ptr);
  15. return;
  16. }
  17. _zend_mm_free_int(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  18. }
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. char *variable="abc";
  6. char **variable_ptr_ptr=variable;
  7.  
  8. char *variable_ptr=*variable_ptr_ptr;
  9.  
  10. char *value="def";
  11. char **value_ptr_ptr=value;
  12. char *value_ptr=*value_ptr_ptr;
  13.  
  14. *variable_ptr_ptr=value_ptr;
  15. return ;
  16. }

变量赋值(引用) php内核的实现(二)的更多相关文章

  1. Makefile笔记之一 ------ 变量的引用及赋值

    1.变量的引用方式: "$(变量名)"或者"¥{变量名}" 例如: ${Objs}就是取变量Objs的值 注意: 当变量名为单字符是可以采用:"$a& ...

  2. PHP:第一章——php中的变量001 /普通赋值/引用赋值/php变量的检查与销毁

    <?php //php中的变量: //php中的变量用一个美元符$后面紧跟着变量名来表示,变量名是区分大小写的. //有效的变量只能是字母或者下划线开头,后面跟任意数量的字母.数字.或者下划线. ...

  3. PHP变量引用赋值与变量赋值变量的区别

    变量默认总是传值赋值.那也就是说,当将一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量.这意味着,例如,当一个变量的值赋予另外一个变量时,改变其中一个变量的值,将不会影响到另外一个变量 ...

  4. 细说PHP-5.3.4变量的引用赋值

    变量总是传值赋值.也就是说,当讲一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量.这意味着,当一个变量的值赋予另个一变量时,改变其中一个变量的值,将不会影响到另一个变量.PHP中提供了 ...

  5. Linux Shell编程变量赋值和引用

    我们可以使用任意一种文字编辑器,比如gedit.kedit.emacs.vi等来编写shell脚本,它必须以如下行开始(必须放在文件的第一行):   #!/bin/sh  ...  注意:最好使用“! ...

  6. Linux —— Shell编程之变量赋值和引用

    Linux的shell编程是一种非常成熟的编程语言,它支持各种类型的变量.有三种主要的变量类型:环境变量.内部变量和用户变量. 环境变量(environment variable)是系统环境的一部分, ...

  7. 变量改变时PHP内核做了些什么?

    引言 内容来自于<Extending and Embedding PHP>- Chaper 3 - Memory Management,加上自己的理解,对php中变量的引用计数.写时复制, ...

  8. Python中的变量、引用、拷贝和作用域

    在Python中,变量是没有类型的,这和以往看到的大部分编辑语言都不一样.在使用变量的时候,不需要提前声明,只需要给这个变量赋值即可.但是,当用变量的时候,必须要给这个变量赋值:如果只写一个变量,而没 ...

  9. 走出 null 就是空值的误区,以及变量赋值原理

    先放一张图片作为引入: 这里我用了一个示意图作为讲解: 平时,我们写的变量为什么能在我们调用它的时候就能被我们拿到所用,跟存钱罐一样,你往里面存一元大洋,它里面就有一元大洋,那么我们的变量在被我们创建 ...

随机推荐

  1. ACE_linux:UDP通信

    1.涉及类 ACE_INET_Addr//ACE网络地址ACE_SOCK_Dgram//ACE报文 2.简介 UDP通信时无需像TCP那样建立连接和关闭连接,TCP编程时需要通过accept和conn ...

  2. PHP随机生成广告图片的实例 代码

    PHP随机生成广告图片: <?php /*  +------------------------------------------------------------------+  | Mi ...

  3. Spark Streaming揭秘 Day23 启动关闭源码图解

    Spark Streaming揭秘 Day23 启动关闭源码图解 今天主要分析一下SparkStreaming的启动和关闭过程. 从Demo程序出发,主要聚焦在两段代码: 启动代码: 关闭代码: 启动 ...

  4. oracle通过透明网关连接mysql的配置

    之前配置过连接TD的,这一篇是介绍连接Mysql的配置很详细. http://blog.itpub.net/12679300/viewspace-1177222/

  5. mongodb命令使用

    最近学习mongodb的使用,整理了一些常用命令 windows服务安装:mongod --install --serviceName MongoDB --serviceDisplayName Mon ...

  6. [摘] SQLPLUS Syntax

    You use the SQLPLUS command at the operating system prompt to start command-line SQL*Plus: SQLPLUS [ ...

  7. UIImageView加抖动效果(转)

    CGAffineTransform moveRight = CGAffineTransformTranslate(CGAffineTransformIdentity, 20, 0); CGAffine ...

  8. 【BZOJ 1412】[ZJOI2009]狼和羊的故事

    Description “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! O ...

  9. 转载:传说中的T检验

    第二周结束:传说中的T检验 小耿2014-01-21 10:58 本文和上一篇笔记一样:语言十分啰嗦.请大家忍耐…… 以前我不懂统计的时候(现在也不懂),只知道数据出来了要做三件事:1,检验一下数据是 ...

  10. eclipse/MyEclipse 日期格式、注释日期格式、时区问题

    eclipse/MyEclipse 日期格式.注释日期格式.时区问题 在eclipse/MyEclipse中,如果你的注释或是运行System.out.print(new java.util.Date ...