Rumah > pembangunan bahagian belakang > tutorial php > php变量的引用赋值与传值赋值的详细介绍(代码)

php变量的引用赋值与传值赋值的详细介绍(代码)

不言
Lepaskan: 2023-04-04 06:16:01
asal
7400 orang telah melayarinya

本篇文章给大家带来的内容是关于php变量的引用赋值与传值赋值的详细介绍(代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

一、使用 memory_get_usage() 查看PHP内存使用量

1. 传值赋值

// 定义一个变量
$a = range(0, 10000);
var_dump(memory_get_usage());

// 定义变量b,将a变量的值赋值给b
$b = $a;
var_dump(memory_get_usage());

// 对a进行修改
// COW: Copy-On-Write
$a = range(0, 10000);
var_dump(memory_get_usage());
Salin selepas log masuk

输出结果:

int(989768)
int(989856)
int(1855608)
Salin selepas log masuk

定义一个变量 $a = range(0, 10000);

3318694436-5b851f10a5d62_articlex.jpg

$b = $a;

4080624257-5b851f10ae86f_articlex.jpg

对a进行修改 $a = range(0, 10000);

1485385066-5b851f10b9b7b_articlex.jpg

PHP写时复制机制(Copy-on-Write,也缩写为COW)

顾名思义,就是在写入时才真正复制一份内存进行修改。
COW最早应用在Unix系统中对线程与内存使用的优化,后面广泛的被使用在各种编程语言中,如C++的STL等。
在PHP内核中,COW也是主要的内存优化手段。
在通过变量赋值的方式赋值给变量时,不会申请新内存来存放新变量的值,而是简单的通过一个计数器来共用内存。只有在其中的一个引用指向变量的值发生变化时,才申请新空间来保存值内容,以减少对内存的占用。
在很多场景下PHP都使用COW进行内存的优化。比如:变量的多次赋值、函数参数传递,并在函数体内修改实参等。

2. 引用赋值

// 定义一个变量
$a = range(0, 10000);
var_dump(memory_get_usage());

// 定义变量b,将a变量的引用赋给b
$b = &$a;
var_dump(memory_get_usage());

// 对a进行修改
$a = range(0, 10000);
var_dump(memory_get_usage());
Salin selepas log masuk

输出结果:

int(989760)
int(989848)
int(989840)
Salin selepas log masuk

定义一个变量 $a = range(0, 10000);

2340912772-5b851f108ae5b_articlex.jpg

定义变量b,将a变量的引用赋给b $b = &$a;

3774805543-5b851f10a5b60_articlex.jpg

对a进行修改 $a = range(0, 10000);

679713656-5b851f105a29e_articlex.jpg

二、使用 xdebug_debug_zval() 查看变量的引用情况

xdebug_debug_zval() 用于显示变量的信息。需要安装xdebug扩展。

1. 传值赋值

$a = 1;
xdebug_debug_zval('a');

// 定义变量b,把a的值赋值给b
$b = $a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

// a进行写操作
$a = 2;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
Salin selepas log masuk

输出结果:

a: (refcount=1, is_ref=0)=1
a: (refcount=2, is_ref=0)=1
b: (refcount=2, is_ref=0)=1
a: (refcount=1, is_ref=0)=2
b: (refcount=1, is_ref=0)=1
Salin selepas log masuk

定义变量 $a = 1;

$a = 1;
xdebug_debug_zval('a');
Salin selepas log masuk
Salin selepas log masuk

输出

a: (refcount=1, is_ref=0)=1
Salin selepas log masuk
Salin selepas log masuk

refcount=1 表示该变量指向的内存地址的引用个数变为1
is_ref=0 表示该变量不是引用

1547227858-5b851f1059ea9_articlex.jpg

定义变量 $b ,把 $a 的值赋给 $b$b = $a;

$b = $a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
Salin selepas log masuk

输出

a: (refcount=2, is_ref=0)=1
b: (refcount=2, is_ref=0)=1
Salin selepas log masuk

refcount=2 表示该变量指向的内存地址的引用个数变为2
is_ref=0 表示该变量不是引用

448181073-5b851f103fd97_articlex.jpg

对变量 $a 进行写操作 $a = 2;

$a = 2;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
Salin selepas log masuk
Salin selepas log masuk

输出

a: (refcount=1, is_ref=0)=2
b: (refcount=1, is_ref=0)=1
Salin selepas log masuk

因为COW机制,对变量 $a 进行写操作时,会为变量 $a 新分配一块内存空间,用于存储变量 $a 的值。
此时 $a 和  $b 指向的内存地址的引用个数都变为1。

1418161517-5b851f1059c5b_articlex.jpg

2. 引用赋值

$a = 1;
xdebug_debug_zval('a');

// 定义变量b,把a的引用赋给b
$b = &$a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

// a进行写操作
$a = 2;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
Salin selepas log masuk
a: (refcount=1, is_ref=0)=1
a: (refcount=2, is_ref=1)=1
b: (refcount=2, is_ref=1)=1
a: (refcount=2, is_ref=1)=2
b: (refcount=2, is_ref=1)=2
Salin selepas log masuk

定义变量 $a = 1;

$a = 1;
xdebug_debug_zval('a');
Salin selepas log masuk
Salin selepas log masuk

输出

a: (refcount=1, is_ref=0)=1
Salin selepas log masuk
Salin selepas log masuk

refcount=1 表示该变量指向的内存地址的引用个数变为1
is_ref=0 表示该变量不是引用

604317911-5b851f103610d_articlex.jpg

定义变量 $b ,把 $a 的引用赋给 $b$b = &$a;

$b = &$a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
Salin selepas log masuk

输出

a: (refcount=2, is_ref=1)=1
b: (refcount=2, is_ref=1)=1
Salin selepas log masuk

refcount=2 表示该变量指向的内存地址的引用个数变为2
is_ref=1 表示该变量是引用

442598603-5b851f0fc4cdd_articlex.jpg

对变量 $a 进行写操作 $a = 2;

$a = 2;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
Salin selepas log masuk
Salin selepas log masuk

输出

a: (refcount=2, is_ref=1)=2
b: (refcount=2, is_ref=1)=2
Salin selepas log masuk

因为变量 $a 和变量 $b 指向相同的内存地址,其实引用。
对变量 $a 进行写操作时,会直接修改指向的内存空间的值,因此变量 $b 的值会跟着一起改变。

184090893-5b851f0fca6b2_articlex.jpg

三、当变量时引用时,unset()只会取消引用,不会销毁内存空间

$a = 1;
$b = &$a;

// unset 只会取消引用,不会销毁内存空间
unset($b);

echo $a;
Salin selepas log masuk

输出

1
Salin selepas log masuk
Salin selepas log masuk

定义变量 $a ,并将 $a 的引用赋给变量  $b

$a = 1;
$b = &$a;
Salin selepas log masuk

2282715878-5b851f0fc3d75_articlex.jpg

销毁 $b

unset($b);
Salin selepas log masuk

4009950758-5b851f0fc8cdc_articlex.jpg

输出 $a

虽然销毁的 $b,但是 $a 的引用和内存空间依旧存在。

echo $a;
Salin selepas log masuk

输出

1
Salin selepas log masuk
Salin selepas log masuk

四、php中对象本身就是引用赋值

class Person
{
    public $age = 1;
}

$p1 = new Person;
xdebug_debug_zval('p1');

$p2 = $p1;
xdebug_debug_zval('p1');
xdebug_debug_zval('p2');

$p2->age = 2;
xdebug_debug_zval('p1');
xdebug_debug_zval('p2');
Salin selepas log masuk
p1: (refcount=1, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }
p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }
p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }
p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 }
p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 }
Salin selepas log masuk

实例化对象 $p1 = new Person;

$p1 = new Person;
xdebug_debug_zval('p1');
Salin selepas log masuk

输出

p1: (refcount=1, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }
Salin selepas log masuk

refcount=1 表示该变量指向的内存地址的引用个数变为1
is_ref=0 表示该变量不是引用

$p1 赋给 $p2

$p2 = $p1;
xdebug_debug_zval('p1');
xdebug_debug_zval('p2');
Salin selepas log masuk

输出

p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }
p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }
Salin selepas log masuk

refcount=2 表示该变量指向的内存地址的引用个数变为2

1112636063-5b851f0fcaf64_articlex.jpg

$p2 中的属性 age 进行写操作

$p2->age = 2;
xdebug_debug_zval('p1');
xdebug_debug_zval('p2');
Salin selepas log masuk

输出

p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 }
p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 }
Salin selepas log masuk

因为php中对象本身就是引用赋值。对 $p2 中的属性 age 进行写操作时,会直接修改指向的内存空间的值,因此变量 $p1age 属性的值会跟着一起改变。

五、实战例题分析

/**
 * 写出如下程序的输出结果
 *
 * $d = ['a', 'b', 'c'];
 *
 * foreach($d as $k => $v)
 * {
 *    $v = &$d[$k];
 * }
 * 
 * 程序运行时,每一次循环结束后变量 $d 的值是什么?请解释。
 * 程序执行完成后,变量 $d 的值是什么?请解释。
 */
Salin selepas log masuk

1. 第一次循环

推算出进入 foreach$v$d[$k] 的值

$k = 0
$v = 'a'
$d[$k] = $d[0] = 'a'
Salin selepas log masuk

此时,$v$d[0] 在内存中分别开辟了一块空间

![$v 和 $d[0] 在内存中分别开辟了一块空间](http://md.ws65535.top/xsj/201...

$v = &$d[0] 改变了 $v 指向的内存地址

$v = &$d[0]
Salin selepas log masuk

![$v = &$d[0] 改变了 $val 指向的内存地址](http://md.ws65535.top/xsj/201...

第一次循环后 $d 的值:

['a', 'b', 'c']
Salin selepas log masuk

2. 第二次循环

进入 foreach$v 被赋值为 'b',此时$v指向的内存地址与 $d[0] 相同,且为引用,因此 $d[0] 的值被修改为 'b'

$v = 'b'  => $d[0] = 'b'

![$v = ‘b’  => $d[0] = ‘b’](http://md.ws65535.top/xsj/201...

推算出进入 foreach$d[$k] 的值

$k = 1
$d[$k] = $d[1] = 'b'
Salin selepas log masuk

![$d[2] = ‘b’](http://md.ws65535.top/xsj/201...

$v = &$d[1] 改变了 $v 指向的内存地址

$v = &$d[1]
Salin selepas log masuk

![$v = &$d[1]](http://md.ws65535.top/xsj/201...

第二次循环后 $d 的值

['b', 'b', 'c']
Salin selepas log masuk

3. 第三次循环

进入 foreach$v 被赋值为 'c',此时$v指向的内存地址与 $d[1] 相同,且为引用,因此 $d[1] 的值被修改为 'c'

$v = 'c'  => $d[1] = 'c'

![$v = ‘c’  => $d[1] = ‘c’](http://md.ws65535.top/xsj/201...

推算出进入 foreach$d[$k] 的值

$k = 2
$d[2] = 'c'
Salin selepas log masuk

![$d[2] = ‘c’](http://md.ws65535.top/xsj/201...

$v = &$d[2] 改变了 $v 指向的内存地址

$v = &$d[2]
Salin selepas log masuk

![$v = &$d[2]](http://md.ws65535.top/xsj/201...

第三次循环后 $d 的值

['b', 'c', 'c']
Salin selepas log masuk

4. 实测

$d = ['a', 'b', 'c'];

foreach ($d as $k=>$v)
{
    $v = &$d[$k];
    print_r($d);
}

print_r($d);
Salin selepas log masuk

输出:

Array
(
    [0] => a
    [1] => b
    [2] => c
)
Array
(
    [0] => b
    [1] => b
    [2] => c
)
Array
(
    [0] => b
    [1] => c
    [2] => c
)
Array
(
    [0] => b
    [1] => c
    [2] => c
)
Salin selepas log masuk

相关推荐:

php 传值赋值与引用赋值的区别_PHP教程

PHP变量赋值、代入给JavaScript中的变量,赋值javascript

Atas ialah kandungan terperinci php变量的引用赋值与传值赋值的详细介绍(代码). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan