>  기사  >  백엔드 개발  >  PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

不言
不言원래의
2018-09-01 16:37:287332검색

이 글은 PHP 변수의 참조 할당 및 값 할당에 대한 자세한 소개(코드)를 제공합니다. 특정 참조 값이 있으므로 도움이 될 수 있습니다.

1. 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());

출력 결과:

int(989768)
int(989856)
int(1855608)

변수 정의 $a = range(0, 10000);

$a = range(0, 10000);

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

$b = $a;

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

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());

输出结果:

int(989760)
int(989848)
int(989840)

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

二、使用 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');

输出结果:

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

定义变量 $a = 1;

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

输出

a: (refcount=1, is_ref=0)=1

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

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

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

输出

a: (refcount=2, is_ref=0)=1
b: (refcount=2, is_ref=0)=1

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

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

$a = 2;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

输出

a: (refcount=1, is_ref=0)=2
b: (refcount=1, is_ref=0)=1

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

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');
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

定义变量 $a = 1;

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

输出

a: (refcount=1, is_ref=0)=1

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

 PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개$b = $a;

🎜PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개🎜🎜🎜🎜$a 수정 = 범위( 0 , 10000);🎜🎜PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개🎜🎜🎜PHP 쓰기 중 복사 메커니즘(Copy-on-Write, 줄여서 COW)🎜🎜이름에서 알 수 있듯이 복사본은 실제로 메모리를 쓸 때 만들어집니다.
COW는 스레드와 메모리 사용을 최적화하기 위해 Unix 시스템에서 처음 사용되었으며 이후 C++의 STL 등 다양한 프로그래밍 언어에서 널리 사용되었습니다.
PHP 커널에서 COW는 주요 메모리 최적화 방법이기도 합니다.
변수 할당을 통해 변수에 값을 할당할 경우, 새로운 변수의 값을 저장하기 위해 새로운 메모리가 할당되지 않고 단순히 카운터를 통해 메모리를 공유하게 됩니다. 참조 중 하나가 가리키는 변수의 값이 변경되는 경우에만 메모리 사용량을 줄이기 위해 값 내용을 저장하기 위해 새로운 공간이 할당됩니다.
많은 시나리오에서 PHP는 메모리 최적화를 위해 COW를 사용합니다. 예를 들어 변수의 다중 할당, 함수 매개변수 전달, 함수 본문의 실제 매개변수 수정 등이 있습니다. 🎜🎜2. 참조 할당🎜
$b = &$a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
🎜출력 결과: 🎜
a: (refcount=2, is_ref=1)=1
b: (refcount=2, is_ref=1)=1
🎜🎜변수 정의 $a = range(0, 10000);🎜🎜PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개🎜🎜🎜 🎜정의 변수 b, 변수 a의 참조를 b $b = &$a;🎜🎜PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개🎜🎜🎜🎜$a = range(0, 10000) ;🎜🎜PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개🎜🎜🎜2. 변수의 참조 상태를 보려면 xdebug_debug_zval()을 사용하세요🎜🎜xdebug_debug_zval()이 사용됩니다 변수 정보를 표시합니다. xdebug 확장을 설치해야 합니다. 🎜🎜1. 값별 할당🎜
$a = 2;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
🎜출력 결과: 🎜
a: (refcount=2, is_ref=1)=2
b: (refcount=2, is_ref=1)=2
🎜🎜변수 정의 $a = 1;
$a = 1;
$b = &$a;

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

echo $a;
🎜Output🎜
1
🎜refcount= 1은 변수가 가리키는 메모리 주소에 대한 참조 개수가 1이 된다는 의미
is_ref=0는 변수가 참조가 아니라는 의미🎜🎜🎜 PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개🎜🎜 🎜🎜정의 변수$b , $a 값을 $b에 할당, $b = $a;
$a = 1;
$b = &$a;
🎜Output🎜
unset($b);
🎜refcount=2는 변수가 가리키는 메모리 주소에 대한 참조 개수가 2개가 된다는 뜻입니다
is_ref =0은 변수가 참조가 아님을 의미합니다🎜 🎜🎜PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개 🎜🎜🎜🎜 변수 $a $a = 2;에 쓰기 >
echo $a;
🎜Output🎜
1
🎜COW 메커니즘으로 인해 변수 $a가 쓰기 작업을 수행하면 $a 변수에 대해 새로운 메모리 공간이 할당됩니다. 변수 $a의 값을 저장합니다.
이때, $a$b가 가리키는 메모리 주소에 대한 참조 개수는 모두 1이 됩니다. 🎜🎜🎜PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개🎜🎜🎜2. 참조 할당🎜
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');
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 }
🎜🎜변수 정의 $a = 1;
$p1 = new Person;
xdebug_debug_zval('p1');
🎜Output🎜
p1: (refcount=1, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }
🎜refcount=1 변수가 가리키는 메모리 주소에 대한 참조 개수가 1개가 됨을 나타냅니다.
is_ref=0 변수가 참조가 아님을 나타냅니다🎜🎜🎜🎜🎜🎜

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

$b = &$a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

输出

a: (refcount=2, is_ref=1)=1
b: (refcount=2, is_ref=1)=1

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

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

$a = 2;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

输出

a: (refcount=2, is_ref=1)=2
b: (refcount=2, is_ref=1)=2

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

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

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

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

echo $a;

输出

1

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

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

销毁 $b

unset($b);

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

输出 $a

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

echo $a;

输出

1

四、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');
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 }

实例化对象 $p1 = new Person;

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

输出

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

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

$p1 赋给 $p2

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

输出

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 }

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

PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개

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

$p2->age = 2;
xdebug_debug_zval('p1');
xdebug_debug_zval('p2');

输出

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 }

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

五、实战例题分析

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

1. 第一次循环

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

$k = 0
$v = 'a'
$d[$k] = $d[0] = 'a'

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

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

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

$v = &$d[0]

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

第一次循环后 $d 的值:

['a', 'b', 'c']

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'

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

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

$v = &$d[1]

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

第二次循环后 $d 的值

['b', 'b', 'c']

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'

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

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

$v = &$d[2]

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

第三次循环后 $d 的值

['b', 'c', 'c']

4. 实测

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

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

print_r($d);

输出:

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
)

相关推荐:

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

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

위 내용은 PHP 변수(코드)의 참조 할당 및 값 할당에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.