Home  >  Article  >  Backend Development  >  PHP变量引用的疑惑

PHP变量引用的疑惑

WBOY
WBOYOriginal
2016-06-23 14:04:58810browse

本以为自己对变量的引用和赋值已经很清楚,结果遇到了下面这个问题,彻底颠覆了我的理解

<?php   $str = 'WangChuanbo';  $s = &$str;  unset($str);  echo $s,'hello world';?>

结果$s输出后还是Wangchuanbo,不是同一块内存地址吗,原变量都被卸载了,引用变量还有值??


回复讨论(解决方案)

张飞姓张名飞字翼德
即 张飞 和 张翼德 是同一个人
你把张飞杀了,只是把张飞这个名字重世间抹去,而那个人还在以张翼德这个称谓到处游逛

张飞姓张名飞字翼德
即 张飞 和 张翼德 是同一个人
你把张飞杀了,只是把张飞这个名字重世间抹去,而那个人还在以张翼德这个称谓到处游逛

说得很有道理,能明白了点,不过还不是很透彻,php的引用机制和C的指针据说有区别,不清楚有什么本质区别?

以前一直觉得这是一个很好的理解引用和赋值的办法:

在Windows系统中, 把E盘上一个文件复制一份到桌面上是赋值,不管修改哪一个,另一个都不会修改; 而在桌面上建一个快捷方式就是引用,不管修改哪一个,另一个都会被修改

这里完全解释不通,好困惑

unset一个引用,只是断开了变量名和变量内容之间的绑定
$s = &$str;在php中的意思是
$s和$str都指向同一个地方C
unset之后$str就找不到C了
我再给你举个例子
小张听小李说财宝在大海上
小李失忆了,但小张还是知道财宝在海上

而在C++中,引用就意味着连内存地址都相同
说到底就是个常量指针

简单的说
C的指针 指向的是内存中特定的地址
C的指针 有个数据类型的概念,因此指针是可以参与运算的
php代码并没有给编译成机器码,所以没就访问内存地址一说
的确php的引用机制和C的指针极其相似,如果不计指针的运算,那么至少在表现上与指针是一样的

首先你得理解PHP的垃圾回收机制,你unset掉一个变量并不是从内存中给抹除了!PHP的垃圾回收是GC来完成的!

unset一个引用,只是断开了变量名和变量内容之间的绑定
$s = &$str;在php中的意思是
$s和$str都指向同一个地方C
unset之后$str就找不到C了
我再给你举个例子
小张听小李说财宝在大海上
小李失忆了,但小张还是知道财宝在海上

而在C++中,引用就意味着连内存地址都相同
说到底就是个常量指针

针对你的解释,我实验了一下

$str = 'WangChuanbo';$s = &$str;$s = 'new';echo $str;


的确是修改了引用变量,原变量也修改了,是我对unset()函数理解不透彻吗,引用可以按照我上面的方式理解不------- 在Windows系统中,把E盘上一个文件复制一份到桌面上是赋值,不管修改哪一个,另一个都不会修改;而在桌面上建一个快捷方式就是引用,不管修改哪一个,另一个都会被修改?

引用 4 楼 franzhong 的回复:unset一个引用,只是断开了变量名和变量内容之间的绑定
$s = &$str;在php中的意思是
而在C++中,引用就意味着连内存地址都相同
……
那当然了,如果你非要这么理解的话,呵呵
你在F盘有个文件夹fff,右健"发送到=〉桌面快捷方式"
然后改名叫aaa,再操作一次,改名叫bbb
打开aaa建个txt在里面,再打开bbb里面也有txt了
不就是这回事嘛

简单的说
C的指针 指向的是内存中特定的地址
C的指针 有个数据类型的概念,因此指针是可以参与运算的
php代码并没有给编译成机器码,所以没就访问内存地址一说
的确php的引用机制和C的指针极其相似,如果不计指针的运算,那么至少在表现上与指针是一样的

有两篇博文我读了几遍,发现每个人都有自己的见解,于是就想把这个问题搞透,
参考一: http://www.nowamagic.net/php/php_ReferenceOperator.php
很多人误解php中的引用跟C当中的指针一样,事实上并非如此,而且很大差别。C语言中的指针除了在数组传递过程中不用显式申明外,其他都需要使用*进行定义,而php中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,php中引用采用的是“写时拷贝”的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的

参考二、 http://blog.csdn.net/woods2001/article/details/7569099

发现越来越困惑了

6楼说的对 要理解这个你需要理解PHP的垃圾回收机制  

PHP 的变量并不像C/C++一样  PHP的变量存储在ZVAL机构中 结构体定义如下
typedef struct _zval_struct zval;
...
struct _zval_struct { 
   /* Variable information */
    zvalue_value value;     /* value */
    zend_uint refcount__gc;    
    zend_uchar type;    /* active type */
    zend_uchar is_ref__gc;
};
zval结构体中有四个字段,其含义分别为:

属性名 含义 默认值 
refcount__gc 表示引用计数 1 
is_ref__gc 表示是否为引用 0 
value 存储变量的值  
type 变量具体的类型 

unset() 并不会直接销毁变量 只有当refcount=0时才会被PHP的垃圾回收机制回收

$a = 10;
xdebug_debug_zval('a'); 
//output: a: (refcount=1, is_ref=0)=10
$b = &$a;
xdebug_debug_zval('a'); 
//output: a: (refcount=2, is_ref=1)=10
$a = 20;
xdebug_debug_zval('a'); 
//output: a: (refcount=2, is_ref=1)=20
unset($b);
xdebug_debug_zval('a'); 
//output: a: (refcount=1, is_ref=0)=20


本帖将会 继续加分,希望大家踊跃发言, 百家争鸣,方才百花齐放

其实很多人在解释引用时都喜欢那php的底层实现来说事,其实这是不对的
解释要用浅显的道理,而非深层次的原理来说明。否则就是越说越乱
就像任何 C 语言书中都不会用汇编语言来解释指针,因为高层都还没明白,底层怎么能明白

php 的引用从表现上看,就如同指针一样。所以把它看成“指针”并无大碍
只是你不要把引用当做“指针”来运算就可以了

换一种方式来理解的话就是
指针是按门牌号码来进出商业街上的每家店铺,所以他可以明确的知道下一家在哪里
引用是按店铺的招牌来进出的,因此他并不能知道旁边的是谁
除此之外,两者的表现并无区别

学习了!

下面希望不要记错:
记忆中php的引用是+1机制,就是每当多一个引用计数器就+1,unset一个就-1
只要变量还有某个单元在使用(不为0),则有效的相关变量名仍然可用

关于这个知识点,我想说三个点:
第一:只有变量才可以有地址,值没有,函数中如果有变量前加&,必须传变量;

        $a=100;    function myfun(&a){ // &后面必须是变量,直接写100不行,必须把100赋给变量$a,写$a        $a++;        return $a;    }    echo myfun($a); //101,  如果写成myfun(100),是错误的

第二:使用UNSET()删除时,只删除 引用关系,并没有删除 值
    $a="aaaaaaaa";    $b=&$a;    unset($b);//unset($b),只删除引用关系,并没有删除值    echo $a; //aaaaaaaa

第三:如果重新给一个变量新的引用,引用关系发生改变;
    $a="aaaaaaaaa";    $c="ccccccccc";    $b=&$a;       $b=&$c;    var_dump($b);// string(9) "ccccccccc" 


在网上帮你找个图片 你看下

这个问题我也在问

这个问题我也在问

你理解的怎么样了?

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn