PHP对象到底是值传递还是引用传递

web360
  • 834

手册:http://php.net/manual/zh/lang...

class A{

}
$a=new A;
$b=$a;
$a->name='haha';
echo '<pre>';
var_dump($b);
var_dump($a);
echo '<hr/>';
function test($obj){
    $obj->name='xixi';
}
test($a);
var_dump($b);
var_dump($a);
echo '<hr/>';
$a=100;
var_dump($a);
var_dump($b);

结果:

clipboard.png

如果说对象是值传递,那么改变对象属性的时候,没有触发copy on write吗

回复
阅读 10.5k
7 个回答
member
  • 6.1k
  1. 对象在函数中是引用传递
  2. 即使赋值给其它变量,也是引用
  3. 但是改变了$a的类型,准确的说是zval.value指针都变化了,所以此时产生了分裂。

所以:

尽量避免函数内操作外部对象,否则有可能造成致命性的逻辑错误,特别是改变对象数据的时候。
或者在做对象数据传递的时候要注意数据的严谨性。

除了加上 clone 关键字,否则都是传引用。

造成这种疑问的,都是把引用当成指针去理解了.

php5之前是值传递:
比如PHP4 有这样的写法 $obj = & new object();

php5之后就不用这样写了:
$obj = new object();

$a和$b是同一个标示符的拷贝,都是指向同一个对象A,所以你改变$a或者$b的属性 其实也就是改变的同一个对象A的属性,但是$a和$b是两个不同的变量,他们两个不是引用关系。
$a=100,这里$a已经是变成整数类型,不再指向对象A了,$b还是指向的对象A。
$b = &$a;你改成这样,$a和$b就是引用关系,后面$b也会输出为100。

Nine
  • 1.1k

其实$a$b都是指向的是对象的标识符,也就是你输出时看到的#1,而这个标识符才是指向的对象。

而当你设置了$b=100时,此时改变了$b的指向,但是并不会影响$a的指向。

clipboard.png

kumfo
  • 6.4k

我看了大家的回答,我仔细阅读和思考了之后,打算也做一份我的答案。

  1. 首先,引用和指针是不一样的,指针在C语言里的概念是表示变量的地址;
  2. 引用在PHP里是表示变量2是变量1的别名,如:
$a = 'hello';
$b = &$a;

此时可以说$b就是$a,$a就是$b;是同一个东西,比如你英文名叫 Steven,中文名叫 二狗子,不管叫啥,都是你。

然后说一下PHP5之后的“对象默认都是引用传递”这件事情。
如:

class Obj() {
    public $o = 'hello';
}
$a = new Obj();
$b = $a;
$c = &$a;

此时,$b=$a其实表示的并不是$b$a的引用,$a$b可以说是没什么关系的,有关系的是实例化Obj类得到的对象。
也就是说,此时$a和$b都是实例化Obj后得到的对象,而$b=$a唯一产生的是$b$a这里得到了实例化Obj后的引用;
然后看$c = &$a
此时是$c$a的引用,也就是说$c就是$a
假设:

unset($b);
unset($c);

那么unset($b)只是删除了实例化Obj后得到的对象的一次引用计数,
unset($c)则删除了$a$b(因为两个表示同一个东西);

同样的,假设:

$a->o = 'test';
echo $b->o; // string 'test'

虽然说$a和$b'没什么关系',但是与实例化后的对象有关系,也就是$a改变的是实例化后的对象的数据,而$b的调用也是调用了这个对象的数据,所以从一定层面上看起来其实是有关系的。

再一个假设这样说还不明白的话,从我们web的业务逻辑来看。

用户A和用户B都登陆了网站,用户A改变了存储评论的数据表的数据,用户B假设去取这条数据,则用户B获取到就是修改后的数据,而其实用户A和用户B是没什么关系的。
而引用其实类似于用户A同时在手机端和电脑端登陆,然后改变了评论数据表的数据,不管是在手机端还是在电脑端重新获取数据都是修改过的,但是实际上就是一个人。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏