PHP 值传递与引用传递

PHP 值传递与引用传递

PHP的传值方式

PHP赋值类型分为两种,传值和传引用,今天我们主要讨论这两种方式在使用上的异同。

普通赋值

<?php
//  Integer
$a = 1111;
$b = $a;
echo $a.PHP_EOL;	// echo  1111
echo $b.PHP_EOL;	// echo  1111
$a = 2222;
echo $a.PHP_EOL;	// echo  2222
echo $b.PHP_EOL;	// echo  1111
// Boolean
$a = TRUE;
$b = $a;
var_dump($a);	// echo  boolean true
var_dump($b);	// echo  boolean true
$a = FALSE;
var_dump($a);	// echo  boolean false
var_dump($b);	// echo  boolean true
// Float
$a = 11.11;
$b = $a;
echo $a.PHP_EOL;	// echo  11.11
echo $b.PHP_EOL;	// echo  11.11
$a = 22.22;
echo $a.PHP_EOL;	// echo  22.22
echo $b.PHP_EOL;	// echo  11.11
// Array
$a = ['1111', '2222'];
$b = $a;
print_r($a);	// echo  Array ( [0] => 1111 [1] => 2222 )
print_r($b);	// echo  Array ( [0] => 1111 [1] => 2222 )
$a[0] = '3333';
$a[1] = '4444';
print_r($a);	// echo  Array ( [0] => 3333 [1] => 4444 )
print_r($b);	// echo  Array ( [0] => 1111 [1] => 2222 )
// Object
class obj{
	public $field = '1111';
}
$a = new obj();
$b = $a;
var_dump($a);	// echo  object(obj)[1] public 'field' => string '1111' (length=4)
var_dump($b);	// echo  object(obj)[1] public 'field' => string '1111' (length=4)
$a->field = '2222';
var_dump($a);	// echo  object(obj)[1] public 'field' => string '2222' (length=4)
var_dump($b);	// echo  object(obj)[1] public 'field' => string '2222' (length=4)

对于普通类型来说(Integer,Float,Boolean,Array),变量赋值类型为值赋值,相当于变量的一份拷贝,赋值后原变量修改不会影响后赋值的变量,对于对象来说,变量赋值为引用传递,传递的是变量的地址,修改变量会影响所有指向这个对象的引用。在函数中使用时同理,普通类型传递值,对象传递引用,函数内对对象的修改会影响函数外的变量,如果确实要传递这个对象而又不想影响外部变量可以考虑使用clone关键字。如下示例:

<?php
class obj{
	public $field = '1111';
}
function test($param) {
	$param->field = '2222';
}
$a = new obj();
$b = $a;
var_dump($a);	// echo  object(obj)[1] public 'field' => string '1111' (length=4)
var_dump($b);	// echo  object(obj)[1] public 'field' => string '1111' (length=4)
test($b);
var_dump($a);	// echo  object(obj)[1] public 'field' => string '2222' (length=4)
var_dump($b);	// echo  object(obj)[1] public 'field' => string '2222' (length=4)
$c = new obj();
$d = clone $c;
var_dump($c);	// echo  object(obj)[1] public 'field' => string '1111' (length=4)
var_dump($d);	// echo  object(obj)[1] public 'field' => string '1111' (length=4)
test($d);
var_dump($c);	// echo  object(obj)[1] public 'field' => string '1111' (length=4)
var_dump($d);	// echo  object(obj)[1] public 'field' => string '2222' (length=4)

传递引用

引用传递采用需要在变量前添加&符号,示例:

<?php
//  Integer
$a = 1111;
$b = &$a;
echo $a.PHP_EOL;	// echo  1111
echo $b.PHP_EOL;	// echo  1111
$a = 2222;
echo $a.PHP_EOL;	// echo  2222
echo $b.PHP_EOL;	// echo  2222
// Boolean
$a = TRUE;
$b = &$a;
var_dump($a);	// echo  boolean true
var_dump($b);	// echo  boolean true
$a = FALSE;
var_dump($a);	// echo  boolean false
var_dump($b);	// echo  boolean false
// Float
$a = 11.11;
$b = &$a;
echo $a.PHP_EOL;	// echo  11.11
echo $b.PHP_EOL;	// echo  11.11
$a = 22.22;
echo $a.PHP_EOL;	// echo  22.22
echo $b.PHP_EOL;	// echo  22.22
// Array
$a = ['1111', '2222'];
$b = &$a;
print_r($a);	// echo  Array ( [0] => 1111 [1] => 2222 )
print_r($b);	// echo  Array ( [0] => 1111 [1] => 2222 )
$a[0] = '3333';
$a[1] = '4444';
print_r($a);	// echo  Array ( [0] => 3333 [1] => 4444 )
print_r($b);	// echo  Array ( [0] => 3333 [1] => 4444 )
// Object
class obj{
	public $field = '1111';
}
$a = new obj();
$b = &$a;
var_dump($a);	// echo  object(obj)[1] public 'field' => string '1111' (length=4)
var_dump($b);	// echo  object(obj)[1] public 'field' => string '1111' (length=4)
$a->field = '2222';
var_dump($a);	// echo  object(obj)[1] public 'field' => string '2222' (length=4)
var_dump($b);	// echo  object(obj)[1] public 'field' => string '2222' (length=4)

当传递引用时,对变量的操作会影响所有的引用该值得变量,对于对象来说本身就是引用传递,所以没有任何区别。按值传递时,php必须复制值。特别是对于大型的字符串和数组来说,这将会是一个代价很大的操作。按引用传递则不需要复制值,对于性能提高很有好处,在使用过程中应该按照实际情况选择引用传递或者值传递。对于函数传参来说,也是一样,只需要在参数前边添加&符。

实战

说了这么多了,是骡子是马拉出来溜溜,看下面这道题:

<?php
$arr = [1, 2, 3];
foreach ($arr as &$v) {
	// no enything
}
foreach ($arr as $v) {
	// no enything
}
prin_r($arr);	// echo Array ( [0] => 1 [1] => 2 [2] => 2 )

在第一个for循环执行结束之后,$v 指向的 $arr[2] 的引用,在执行第二个for循环的时候,第一个循环开始是,将 $arr[0] 赋值给 $v,就相当于将 $arr[0] 赋值给 $arr[2],第二次循环是将 $arr[1] 辅助给 $arr[2],第三次赋值是将 $arr[2] 赋值给 $arr[2],赋值给自身,每次循环打印出来的话如下所示:

<?php
$arr = [1, 2, 3];
foreach ($arr as &$v) {
	// no enything
}
foreach ($arr as $k => $v) {
	echo '第'.(++$k).'次循环:';
	print_r($arr);
}
// echo 第1次循环: Array ( [0] => 1 [1] => 2 [2] => 1 )
// echo 第2次循环: Array ( [0] => 1 [1] => 2 [2] => 2 )
// echo 第3次循环: Array ( [0] => 1 [1] => 2 [2] => 2 )

这个挺好理解的,将循环拆解之后便一目了然,再来看下面这道:

<?php
$arr = [1, 2, 3];
foreach ($arr as $k => $v) {
	$v = &$arr[$k];
}
print_r($arr);	//echo Array ( [0] => 2 [1] => 3 [2] => 3 )

怎么样,和你想的一样么,这个比上面的那道更难一些,是将上面的两个循环结合在一起,跟复杂一些,在第一次循环结束时,$v 指向 $arr[0],第二次循环时开始时,$arr[1] 赋值给 $v 相当于赋值给 $arr[0],第二次循环结束时 $v 指向 $arr[1],第三次循环开始时将 $arr[2] 赋值给 $v 相当于赋值给了 $arr[1],第三次循环什么都没做,简单来说就是每次循环将第 (i) 个元素的值赋值到 (i-1) 的位置上,打印输出一下:

<?php
$arr = [1, 2, 3];
foreach ($arr as $k => $v) {
	$v = &$arr[$k];
	echo '第'.(++$k).'次循环:';
	print_r($arr);
}
// echo 第1次循环: Array ( [0] => 1 [1] => 2 [2] => 3 )
// echo 第2次循环: Array ( [0] => 2 [1] => 2 [2] => 3 )
// echo 第3次循环: Array ( [0] => 2 [1] => 3 [2] => 3 )

这两道题咋一看之下有点懵,但是细想之下是考察对于循环和引用的理解,越是细节的东西越要在意,越是基础的东西越要理解,基础打好了才能进步的更快啊。

猜你喜欢

转载自blog.csdn.net/lxy_8090/article/details/85014468