php 引用传递和值传递深入解析

PHP 值传递和引用传递的区别。什么时候传值什么时候传引用

先来张图,然后再讲后面的
php 引用传递和值传递深入解析

按值传递

函数范围内对值的任何改变在函数外部都会被忽略
值传递是把值拷贝一份,两个变量指向两个内存地址

值传递没什么好说的,就是普通的赋值,如下:

$a = 6;
$b = $a; // 这是值传递,把 $a 的值拷贝给了 $b,在内存中 $a 和 $b 不在一个地址中,更改任意变量的值对对方无影响
$b = 7;
echo $a; // 输出:6

function foo($b){
	echo ++$b;
}
foo($b); // 输出:8   
echo $b; // 输出:7    说明函数内的改变对函数外的值没有影响,因为,当 $b 传入函数内的时候是值传递,会把值在内存中拷贝一份存入一个新的内存地址中 
按引用传递

函数范围内对值的任何改变在函数外部也能反映出这些修改
引用传递是将一个变量的内存地址标识传给了内外一个变量,两个变量最终指向内存同一个地址
引用传值一

重点是引用传递
以及引用传递易犯错误说明,如下:

$a = 6;
$b = &$a;
$b = 7;
echo $a; // 输出:7 

function foo(&$c){
	echo ++$c;
}
foo($b); // 输出:8   
echo $b; // 输出:8    说明函数内的改变对函数外的值有影响,因为,当 $b 传入函数内的时候是引用传递,函数体内的$b和外部的$b实际上是指向同一个内存地址,所以一个改变,另外一个变量的值也会改变

引用传值进阶示例:

function func(&$arr){
	$arr['a'] = [];
	$arr = &$arr['a'];
	$arr['b'] = '333';
	var_dump($arr); 
	/**
	 * 输出:
	 * array(1) {
     *    ["b"]=> string(3) "333"
     * }
	 */
}
$arr = [
    'a' => '111',
    'b' => '222'
];
func($arr);
var_dump($arr);
/**
 1. 输出:
 2. array(2) {
 3.    ["a"]=>
 4.    array(1) {
 5.         ["b"]=>
 6.         string(3) "333"
 7.    }
 8.    ["b"]=> string(3) "222"
 9. }
 */

上面的示例明明还是引用传递进去的为啥会两个 $arr 打印出不一样的结果呢?
因为里面有一步操作 $arr = &$arr['a']; 这一步之后函数内的 $arr 的指向地址已经改变,指向了$arr['a'],所以两次打印的结果不一样

注意

  1. php 中对于对象默认引用传值
  2. 一般引用传值用在需要在函数体内改变传入参数并且需要影响外部变量的时候使用,其他时候一般使用值传递

PHP写时拷贝

php 中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由 Zend 核心实现的,php 中引用采用的是 “写时拷贝” 的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的。

通俗的讲
1: 如果有下面的代码

 $a="ABC";
 $b=$a;

其实此时 $a 与 $b 都是指向同一内存地址而并不是 $a 与 $b 占用不同的内存
2: 如果在上面的代码基础上再加上如下代码

$a="EFG";

由于 $a 与 $b 所指向的内存的数据要重新写一次了,此时 Zend 核心会自动判断自动为 $b 生产一个 $a 的数据拷贝,重新申请一块内存进行存储。

php 引用于 C 指针的区别

在 PHP 中引用的意思是:不同的名字访问同一个变量内容.
与C语言中的指针是有差别的.C语言中的指针里面存储的是变量的内容在内存中存放的地址。
PHP 的引用允许你用两个变量来指向同一个内容(引用传值相当于给变量起了个别名)
当你 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。

可能对你理解这个示例有帮助的文章:
1、指针和内存
2、一 维数组和二维数组内存示意图
3、十个 PHP 开发者最容易犯的错误
4、php 函数值传值 / 地址以及引用的用法