php函数值传值/地址以及引用的用法
博客摘自 奔跑的大白,网址: http://www.cnblogs.com/gauze/p/5568867.html
1.先来解释一下名词。
值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。
引用传递(pass-by-reference)过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的。
注意:上面红字部分说明,应用传递不是不开辟空间,是开辟空间的,只不过开辟的空间是用来存放实参变量地址的。
2.php中引用的用法有以下三种。
①. 变量的引用赋值: $a = &$b
②. 函数调用时的引用参数传递
1) 早期php是在调用时通过&符号传递引用类型的变量, 比如: func(&$arg);
2) 后来, 函数的引用类型参数被规定为需要在函数声明时定义, 不如: function func(&$arg);
注意:引用声明时定义引用类型参数后,运行时引用参数传递被废弃,需要在php.ini中增加allow_call_time_pass_reference来开启.
③. 函数返回引用类型,这种应用方式需要声明函数时,在函数名前增加&符号,并且,在调用时,要用引用赋值方式, 实例代码如下:
1
2
3
4
5
|
function &func() { return $a ; } $a = func(); //这种调用方式得到的不是引用传值 $a =& func(); //这样调用才是引用传值 |
请看下面详细的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$a = 1; function &func(& $a ) { return $a ; } $b = func( $a ); $c =& func( $a ); $b = 2; echo "a: $a, b: $b, c: $c. <br />/n" ; //输出a: 1, b: 2, c: 1. //可见对$b的修改不会影响$a $c = 3; echo "a: $a, b: $b, c: $c. <br />/n" ; //输出a: 3, b: 2, c: 3. //可见对$c的修改会影响$a |
3.php各种数据类型传值/指针
一、基本数据类型的传值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/* **************************************************** */ function testvar( $k ){ $k = 40; } $c = 30; //给一个函数参数传一个基本数据类型(整型,布尔,字符 ...), 实际上传的就是值 ; testvar( $c ); echo $c ; //结果是:30 function testvar2(& $k ){ $k = 40; } $e = 30; //给一个函数参数传一个基本数据类型(整型,布尔,字符 ...), 实际上传的y就是地址 ; testvar2( $e ); echo $e ; //结果是:40 /* **************************************************** */ |
二、数组(默认情况下是复制一份数据),如要传地址则&$arr
1 $arr1 = array(-1,5,0); 2 function testArr($arr){ 3 for($i=0;$i<count ($arr);$i++){ 4 for($j=$i+1;$j<count($arr);$j++){ 5 if($arr[$i]>$arr[$j]){ 6 $temp = $arr[$i]; 7 $arr[$i] = $arr[$j]; 8 $arr[$j] = $temp; 9 } 10 } 11 12 } 13 print_r($arr); //结果:Array ( [0] => -1 [1] => 0 [2] => 5 ) 14 } 15 testArr($arr1); 16 print_r($arr1); //结果:Array ( [0] => -1 [1] => 5 [2] => 0 ) 17 18 function testArr2(&$arr){ 19 for($i=0;$i</count><count ($arr);$i++){ 20 for($j=$i+1;$j<count($arr);$j++){ 21 if($arr[$i]>$arr[$j]){ 22 $temp = $arr[$i]; 23 $arr[$i] = $arr[$j]; 24 $arr[$j] = $temp; 25 } 26 } 27 28 } 29 } 30 testArr($arr1); 31 print_r($arr1); //结果:Array ( [0] => -1 [1] => 0 [2] => 5 )
三、对象数据类型传值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class person{ public $name ; public $age ; } $a = new person(); $a ->name = '小明' ; $a ->age = '20' ; //变量a在存的是对象的地址,把a赋给b这个变量,实际上就是赋了一个地址。 $b = $a ; $b ->age = 30; //echo $a->age.$b->age;//结果是:30 30 //给一个函数参数传一个对象, 实际上传的是这个对象的地址; function test( $k ){ $k ->age =40; } //调用 test( $b ); //echo $a->age.$b->age;//结果是:40 40 |
在PHP5中 对象的复制 是通过引用来实现的。上列中$a=new person; $b=$a; 其实等效于$a=new person; $b=&$a;
PHP5中默认就是通过引用来调用对象, 但有时你可能想建立一个对象的副本,并希望原来的对象的改变不影响到副本 . 为了这样的目的,PHP定义了一个特殊的方法,称为__clone.
4.php写时拷贝
php中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,php中引用采用的是“写时拷贝”的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的。
通俗的讲
1:如果有下面的代码
$a="ABC";
$b=$a;
其实此时$a与$b都是指向同一内存地址而并不是$a与$b占用不同的内存
2:如果在上面的代码基础上再加上如下代码
$a="EFG";
由于$a与$b所指向的内存的数据要重新写一次了,此时Zend核心会自动判断自动为$b生产一个$a的数据拷贝,重新申请一块内存进行存储。
5.php引用于C指针的区别
在PHP 中引用的意思是:不同的名字访问同一个变量内容.
与C语言中的指针是有差别的.C语言中的指针里面存储的是变量的内容在内存中存放的地址。
PHP 的引用允许你用两个变量来指向同一个内容
1
2
3
4
5
6
7
|
$a = "ABC" ; $b =& $a ; echo $a ; //这里输出:ABC echo $b ; //这里输出:ABC $b = "EFG" ; echo $a ; //这里$a的值变为EFG 所以输出EFG echo $b ; //这里输出EFG |
当你 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。例如:
1
2
|
unset( $a ); echo $b ; //这里输出EFG |
6. ref:
http://blog.sina.com.cn/s/blog_664c9f650101fl4b.html
http://www.2cto.com/kf/201110/108970.html
http://www.phpfensi.com/php/20140220/1612.html
1.先来解释一下名词。
值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。
引用传递(pass-by-reference)过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的。
注意:上面红字部分说明,应用传递不是不开辟空间,是开辟空间的,只不过开辟的空间是用来存放实参变量地址的。
2.php中引用的用法有以下三种。
①. 变量的引用赋值: $a = &$b
②. 函数调用时的引用参数传递
1) 早期php是在调用时通过&符号传递引用类型的变量, 比如: func(&$arg);
2) 后来, 函数的引用类型参数被规定为需要在函数声明时定义, 不如: function func(&$arg);
注意:引用声明时定义引用类型参数后,运行时引用参数传递被废弃,需要在php.ini中增加allow_call_time_pass_reference来开启.
③. 函数返回引用类型,这种应用方式需要声明函数时,在函数名前增加&符号,并且,在调用时,要用引用赋值方式, 实例代码如下:
1
2
3
4
5
|
function &func() { return $a ; } $a = func(); //这种调用方式得到的不是引用传值 $a =& func(); //这样调用才是引用传值 |
请看下面详细的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$a = 1; function &func(& $a ) { return $a ; } $b = func( $a ); $c =& func( $a ); $b = 2; echo "a: $a, b: $b, c: $c. <br />/n" ; //输出a: 1, b: 2, c: 1. //可见对$b的修改不会影响$a $c = 3; echo "a: $a, b: $b, c: $c. <br />/n" ; //输出a: 3, b: 2, c: 3. //可见对$c的修改会影响$a |
3.php各种数据类型传值/指针
一、基本数据类型的传值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/* **************************************************** */ function testvar( $k ){ $k = 40; } $c = 30; //给一个函数参数传一个基本数据类型(整型,布尔,字符 ...), 实际上传的就是值 ; testvar( $c ); echo $c ; //结果是:30 function testvar2(& $k ){ $k = 40; } $e = 30; //给一个函数参数传一个基本数据类型(整型,布尔,字符 ...), 实际上传的y就是地址 ; testvar2( $e ); echo $e ; //结果是:40 /* **************************************************** */ |
二、数组(默认情况下是复制一份数据),如要传地址则&$arr
1 $arr1 = array(-1,5,0); 2 function testArr($arr){ 3 for($i=0;$i<count ($arr);$i++){ 4 for($j=$i+1;$j<count($arr);$j++){ 5 if($arr[$i]>$arr[$j]){ 6 $temp = $arr[$i]; 7 $arr[$i] = $arr[$j]; 8 $arr[$j] = $temp; 9 } 10 } 11 12 } 13 print_r($arr); //结果:Array ( [0] => -1 [1] => 0 [2] => 5 ) 14 } 15 testArr($arr1); 16 print_r($arr1); //结果:Array ( [0] => -1 [1] => 5 [2] => 0 ) 17 18 function testArr2(&$arr){ 19 for($i=0;$i</count><count ($arr);$i++){ 20 for($j=$i+1;$j<count($arr);$j++){ 21 if($arr[$i]>$arr[$j]){ 22 $temp = $arr[$i]; 23 $arr[$i] = $arr[$j]; 24 $arr[$j] = $temp; 25 } 26 } 27 28 } 29 } 30 testArr($arr1); 31 print_r($arr1); //结果:Array ( [0] => -1 [1] => 0 [2] => 5 )
三、对象数据类型传值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class person{ public $name ; public $age ; } $a = new person(); $a ->name = '小明' ; $a ->age = '20' ; //变量a在存的是对象的地址,把a赋给b这个变量,实际上就是赋了一个地址。 $b = $a ; $b ->age = 30; //echo $a->age.$b->age;//结果是:30 30 //给一个函数参数传一个对象, 实际上传的是这个对象的地址; function test( $k ){ $k ->age =40; } //调用 test( $b ); //echo $a->age.$b->age;//结果是:40 40 |
在PHP5中 对象的复制 是通过引用来实现的。上列中$a=new person; $b=$a; 其实等效于$a=new person; $b=&$a;
PHP5中默认就是通过引用来调用对象, 但有时你可能想建立一个对象的副本,并希望原来的对象的改变不影响到副本 . 为了这样的目的,PHP定义了一个特殊的方法,称为__clone.
4.php写时拷贝
php中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,php中引用采用的是“写时拷贝”的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的。
通俗的讲
1:如果有下面的代码
$a="ABC";
$b=$a;
其实此时$a与$b都是指向同一内存地址而并不是$a与$b占用不同的内存
2:如果在上面的代码基础上再加上如下代码
$a="EFG";
由于$a与$b所指向的内存的数据要重新写一次了,此时Zend核心会自动判断自动为$b生产一个$a的数据拷贝,重新申请一块内存进行存储。
5.php引用于C指针的区别
在PHP 中引用的意思是:不同的名字访问同一个变量内容.
与C语言中的指针是有差别的.C语言中的指针里面存储的是变量的内容在内存中存放的地址。
PHP 的引用允许你用两个变量来指向同一个内容
1
2
3
4
5
6
7
|
$a = "ABC" ; $b =& $a ; echo $a ; //这里输出:ABC echo $b ; //这里输出:ABC $b = "EFG" ; echo $a ; //这里$a的值变为EFG 所以输出EFG echo $b ; //这里输出EFG |
当你 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。例如:
1
2
|
unset( $a ); echo $b ; //这里输出EFG |
6. ref:
http://blog.sina.com.cn/s/blog_664c9f650101fl4b.html
http://www.2cto.com/kf/201110/108970.html
http://www.phpfensi.com/php/20140220/1612.htm