3.2 变量
PHP更多时候使用变量实现数据在内存中的存储,变量是PHP表达式中最重要的组成部分。PHP变量可分为自定义变量和预定义变量,本章所谈到的变量为自定义变量。
3.2.1 变量基本概念
变量是用于临时存储数据的容器,这些数据可以是任意一种数据类型的数据。变量通过变量名实现内存数据的按名存取。PHP中的变量名遵循以下规则。
(1)变量名必须以美元符号($)开头,如$userName。
(2)变量名的第1个字符必须是字母或下画线(不能是数字),变量名称可以为字母、数字和下画线的组合,如$user_name_1。
(3)PHP 中的变量名是区分大小写的,这是一个非常重要的规则。这意味着$userName 和$UserName是截然不同的两个变量。
和传统的高级语言不一样,PHP中对于已经定义的变量可以通过重新赋值的方法修改该变量的值,甚至修改该变量的数据类型。例如,程序variable.php如下。
<?php
//以下语句修改$userName变量的值
$userName = "张三";
$userName = "李四";
//以下语句既修改$sex变量的值,又修改了$sex变量的数据类型
$sex = FALSE;
$sex = "男";
?>
3.2.2 变量的内存分配
内存除了存在一个常量存储区专门用于存储常量外,还有一段栈空间用于存储变量。栈是一种数据结构,它是一种只能在某一端插入和删除的特殊线性表。栈按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,栈底固定,而栈顶浮动。插入一个元素的过程称为入栈(PUSH),删除一个元素的过程则称为出栈(POP)。栈的逻辑结构如图3-3所示。程序variable.php运行过程中的内存分配图如图3-4所示。
对图3-4说明如下。
(1)程序准备执行时,内存处于初始状态,此时栈内存和内存中没有任何数据。
(2)程序执行到“$userName = "张三";”语句时,称为过程1。过程1后,栈内存和内存中将添加变量$userName及对应的值"张三"。
(3)程序执行到“$userName = "李四";”语句时,称为过程2。过程2后,内存中将添加变量$userName对应的值"李四"。
(4)此后由于内存中"张三"数据没有被其他变量名所引用(指向),"张三"将视为垃圾数据被PHP垃圾回收机制在“适当”时刻回收,以便节省内存开支,该过程称为过程3。
(5)程序执行到“$sex = FALSE;”语句时,称为过程4。过程4后,栈内存和内存中将添加变量$sex及对应的值FALSE。
(6)程序执行到“$sex = "男";”语句时,称为过程5。过程5后,内存中将添加变量$sex对应的值"男"。
(7)此后由于FALSE在内存中没有被其他变量名所引用(指向),FALSE将被视为垃圾数据被PHP垃圾回收机制在“适当”时刻回收,以便节省内存开支。该过程称为过程6。
(8)当程序 variable.php 中的所有代码执行完毕后,PHP 垃圾回收机制首先回收位于栈顶的变量$sex,该过程为过程7。
(9)最后PHP垃圾回收机制回收位于栈底的变量$userName,该过程为过程8。过程8后,内存又处于初始状态,为运行其他PHP程序做准备。
3.2.3 变量赋值方式
变量赋值是指赋予变量具体的数据,使用赋值运算符“=”来实现。PHP提供两种赋值方式:传值赋值和传地址赋值。
1.传值赋值方式
前面所有的程序都是使用传值赋值方式为变量赋值,传值赋值方式将一个值的“拷贝”赋值给某个变量。例如,程序byValue.php如下,该程序运行过程中的内存分配图如图3-5所示。
<?php
$age1 = 18;
//以下语句进行传值赋值,变量$age1的值18赋值给变量$age2
$age2 = $age1;
//以下语句修改变量$age2的值,此时变量$age2在内存中开辟新的空间存储值20
$age2 = 20;
echo $age1; //该语句输出$age1变量的值为18
echo "<br/>";
echo $age2; //该语句输出$age2变量的值为20
?>
对图3-5的部分说明如下。
(1)当程序执行到“$age2 = $age1;”语句时,称为过程2。过程2后,内存中并没有新增变量$age2的变量值18,这是由于PHP为了提高内存的使用效率,采用了“写时拷贝”的原理对变量进行赋值。简言之,除非发生写(或修改)操作,否则指向同一个地址的变量值或者对象将不会被拷贝,这样既节省内存又提高了代码的执行效率。
(2)当程序执行到“$age2 = 20;”语句时,称为过程3。过程3后,内存才添加了变量$age2的变量值20。
2.传地址赋值方式
传地址赋值是将源变量的内存地址赋值给新的变量,即新的变量引用了源变量的值,改动新变量的值将影响到源变量的值,反之亦然。传地址赋值意味着两个变量都指向同一个数据,不存在任何数据的拷贝过程。PHP通过在源变量($oldVariable)前追加“&”符号实现传地址赋值,语法格式为:$newVariable = &$oldVariable。例如程序byReference.php如下,该程序运行过程中的内存分配图如图3-6所示。
<?php
$age1 = 18;
//进行传地址赋值,变量$age1的地址(引用)赋值给变量$age2
$age2 = &$age1;
$age2 = 20;
echo $age1; //该语句输出$age1变量的值为20
echo "<br/>";
echo $age2; //该语句输出$age2变量的值为20
?>
对图3-6的部分说明如下。
(1)当程序执行到“$age2 = &$age1”;语句时,称为过程2。经过过程2后,变量$age2与变量$age1指向了内存中同一个变量值18。
(2)当程序执行到“$age2 = 20”;语句时,称为过程3。过程3后,变量$age2与变量$age1指向了内存中同一个变量值20。
3.2.4 可变变量
PHP提供了一种特殊类型的变量:可变变量。可变变量允许PHP程序动态地改变一个变量的变量名,可变变量的工作原理是用一个变量的“值”作为另一个变量的“名”。例如,程序variableNameChanged.php如下。
<?php
$varname = "age";
//用$$varname取代$age。下面的代码等价于:$age = 20;
$$varname = 20;
echo $age; //输出$age变量的值:20
?>
在定义可变变量时,可能会出现歧义。例如,在可变变量$$age[1]中,将$age[1]作为一个变量,还是将$$age 作为一个变量并取出该变量中“键”值为 1 的值?为了解决这样的歧义,可以使用${$age[1]}和${$age}[1]分别来表示上述两种情况。
共有条评论 网友评论