在记忆中 PHP 简单变量的拷贝是按值传递,数组和对象的拷贝是按引用传递,即通过引用来实现。

简单变量和对象好理解:

<?php

// 简单变量的拷贝
$a = 'human';
$b = $a;
$b = 'cat';
var_dump($a); // string 'human' (length=5) // 对象的拷贝
class A{}
$a = new A();
$b = $a;
$b->name = 'jack';
var_dump($a); // object(A)[1] public 'name' => string 'jack' (length=4)

对象 $a 和 对象 $b 的内存地址指向了同一个地方,即针对 $a 和 $b 所做的操作都针对同一个实例。

PHP 中可以通过 clone 关键字按值拷贝对象:

<?php

class A{
public $name = 'Vardy';
}
$a = new A();
$b = clone $a;
$b->name = 'dee';
var_dump($a); // object(A)[1] public 'name' => string 'Vardy' (length=5)
var_dump($b); // object(A)[2] public 'name' => string 'dee' (length=3)

  

数组:

<?php

// 数组的拷贝
$a = ['human', 'orc'];
$b = $a;
$b[0] = 'elve';
var_dump($a);
// array (size=2)
// 0 => string 'human' (length=5)
// 1 => string 'orc' (length=3)

这样看,数组的拷贝是按值传递的.

另一个例子 数组的迭代器:

<?php

$a = ['human', 'orc', 'elven', 'undead'];
next($a); $b = $a; // 此时指针位置也随着数组的复制而复制 var_dump(current($a)); // string 'orc' (length=3)
var_dump(current($b)); // string 'orc' (length=3)

当数组拷贝时,数组的指针位置也随着复制。

(next:http://php.net/manual/zh/function.next.php

current:http://php.net/manual/zh/function.current.php

<?php

$a = ['human', 'orc', 'elven', 'undead'];
end($a);
next($a); // 数组指针非法,返回 FALSE $b = $a; var_dump(current($a)); // string 'human' (length=5)
var_dump(current($b)); // boolean false

当数组在拷贝前,指针的位置是非法时,拷贝后分别打印两个数组指针所指向的当前单元时,出现了不一样的情况。

原因是数组变量发生拷贝后,两个变量中先发生写操作的,其指针被初始化,即指向第一个元素,而 current 方法也会产生写操作,因此 $a 的数组指针当前指向的是 'human',而 $b  current 方法则返回 FALSE。

以下代码同理, $b 首先发生了写操作:

<?php

$a = ['human', 'orc', 'elven', 'undead'];
end($a);
next($a); $b = $a; $b[] = 'dwarf'; var_dump(current($a)); // boolean false
var_dump(current($b)); // string 'human' (length=5)

  

解析:数组的拷贝是值传递。PHP 在管理内存方面有一个机制叫写时复制(COW,Copy On Write),保证了变量间复制值不浪费内存:当一个变量的值复制到另一个变量时,PHP 没有为复制值使用更多的内存,相反,它会更新符号表来说明两个变量拥有相同的内存块,所以当执行下面的代码时并没有创建一个新的数组:

<?php

$a = ['human', 'orc', 'elven', 'undead'];
$b = $a;

当修改了 $a 或 $b 任意一个副本时,PHP 将分配所需的内存来进行复制:

$b[] = 'dwarf';

  

 

参考:

php基础语法之数组和数组指针

php中引用&的真正理解-变量引用、函数引用、对象引用

Programming PHP 3rd Edition

最新文章

  1. 那些年使用Hive踩过的坑
  2. Redis在windows下的安装使用
  3. Winform开发框架之介绍
  4. WaitForSingleObject 和 WaitForMultipleObjects函数
  5. Drupal如何更新注册表?
  6. 關於NPOI的一點補充和示例
  7. C++结构体:默认构造函数,复制构造函数,重载=运算符
  8. C#使用FFmpeg 将视频格式转换成MP4示例
  9. 给EditText的drawableRight属性的图片设置点击事件
  10. Linux时间子系统之(十七):ARM generic timer驱动代码分析
  11. $_SERVER服务器端
  12. struct与class的区别
  13. Python类继承(转发)
  14. Maven 项目中的 pom.xml 文件内容说明
  15. 自学Python6.4-内置模块(2)
  16. 【BZOJ4813】[CQOI2017]小Q的棋盘(贪心)
  17. WPF RichTextBox相关总结
  18. 解决Linux 下 root用户删除文件提示:Operation not permitted
  19. Guava ClassToInstanceMap
  20. Ubuntu下安装软件、卸载

热门文章

  1. sdcms标签
  2. column css3 列宽
  3. C语言中史上最愚蠢的Bug
  4. CSS代码片段【图文】
  5. 百度地图用ip获取当前位置的经纬度(高精度)
  6. dynamic和var的区别
  7. [Linux]系统调用理解(2)
  8. SQL语句执行效率及分析(note)
  9. Shell判断字符串包含关系的几种方法
  10. Windows下安装Redis