变量作用域这概念,就是一个变量在程序里能被访问到的范围。学PHP那会儿,我在这儿踩过不少坑,尤其是全局变量在函数里用不了的问题,当时愣是找了半天原因。
PHP的变量作用域分成三种:局部变量、全局变量、静态变量。下面一个个说清楚。
一、局部变量
在函数内部声明的变量,就叫局部变量。这玩意儿只在它所在的函数里有效,函数外面访问不到。
<?php
function code_sign()
{
$course = "PHP变量教程"; // 局部变量
echo "函数内部输出: ". $course;
}
code_sign();
?>
输出:
函数内部输出: PHP变量教程
再来个反面例子,看看外面访问会怎样:
<?php
function show_lang()
{
$lang = "Python";
echo "函数内部: " . $lang;
}
show_lang();
// 下面这行会报错,因为$lang在函数外面不存在
echo $lang;
?>
输出:
函数内部: Python
Notice: Undefined variable: lang in ...
个人经验: 刚开始写代码时,我老喜欢在函数外面直接调用函数里面的变量,结果到处报错。后来养成习惯,函数里用的变量就在函数里定义好,或者用返回值传出来。函数外面同名的变量和函数里面的变量是两码事,各是各的内存空间。
二、全局变量
全局变量定义在函数外面,理论上整个程序都能访问。但有个坑:想在函数内部直接用全局变量,不行,得加global关键字。
<?php
$user_name = "李明"; // 全局变量
function show_global()
{
global $user_name; // 不加这行,函数里认不出$user_name
echo "函数内部获取: ". $user_name;
echo "</br>";
}
show_global();
echo "函数外部直接获取: ". $user_name;
?>
输出:
函数内部获取: 李明
函数外部直接获取: 李明
为什么函数内部不能直接用全局变量?
PHP的设计思路是函数应该独立、封闭,避免函数内部意外修改外部变量。所以想用,就得明确声明global。
如果不加global会怎样?
<?php
$user_name = "李明"; // 全局变量
function show_global()
{
// 没有global声明,$user_name在函数里是undefined
echo "函数内部: ". $user_name;
}
show_global();
?>
输出:
Notice: Undefined variable: user_name in ...
函数内部:
用$GLOBALS数组代替global
除了global关键字,PHP还提供了$GLOBALS超全局数组,也能在函数里访问全局变量。
<?php
$price_a = 120;
$price_b = 80;
function calc_total()
{
$total = $GLOBALS['price_a'] + $GLOBALS['price_b'];
echo "总价: " . $total;
}
calc_total();
?>
输出:
总价: 200
$GLOBALS是个关联数组,变量名就是键名。个人习惯用$GLOBALS的时候多一些,因为不用在每个函数里重复写global声明,代码看着更直观。
同名变量:局部优先于全局
函数内部如果有和全局变量同名的局部变量,优先用局部的。
<?php
$score = 85;
function check_score()
{
$score = 92; // 这是局部变量
echo "函数内部值: " . $score;
}
check_score();
?>
输出:
函数内部值: 92
函数外部的$score还是85,没被影响。这是好事——函数内部操作不会污染全局数据。
本节课程知识要点: 函数内部想用全局变量,要么写
global $变量名,要么用$GLOBALS['变量名']。全局变量和局部变量同名时,函数内部优先使用局部变量。
三、静态变量
普通局部变量,函数执行完就销毁了,内存释放。但有时候我们需要保留函数内部某个变量的值,下次调用函数时还能用上次的结果。这时候就用静态变量。
定义静态变量用static关键字。
<?php
function counter()
{
static $count = 0; // 静态变量,只初始化一次
$temp = 0; // 普通局部变量,每次调用都重新初始化
$count++;
$temp++;
echo "静态变量count: " . $count . "</br>";
echo "普通变量temp: " . $temp . "</br>";
}
// 第一次调用
counter();
// 第二次调用
counter();
?>
输出:
静态变量count: 1
普通变量temp: 1
静态变量count: 2
普通变量temp: 1
看到区别没?$count每次调用都在上一次基础上加1,$temp每次调用都是从0开始加1。
静态变量的特点:
-
只在函数内部可见,外部访问不了
-
函数执行完不释放内存,值保留
-
初始化只执行一次(第一次调用函数时)
-
同一个函数多次调用时,静态变量会保持上次的值
实际能用在哪里?
比如做一个函数调用次数统计:
<?php
function record_visit()
{
static $times = 0;
$times++;
echo "这个函数被调用了 " . $times . " 次</br>";
}
record_visit(); // 第1次
record_visit(); // 第2次
record_visit(); // 第3次
?>
输出:
这个函数被调用了 1 次
这个函数被调用了 2 次
这个函数被调用了 3 次
个人建议: 静态变量好用,但别乱用。递归函数里慎用静态变量,值会累加导致意料之外的结果。如果只是需要记录状态,静态变量比全局变量更干净——它不会污染全局命名空间,又能保留状态。
核心概念速查
| 类型 | 定义位置 | 访问方式 | 生命周期 |
|---|---|---|---|
| 局部变量 | 函数内部 | 直接使用变量名 | 函数执行完就销毁 |
| 全局变量 | 函数外部 | 函数外用变量名;函数内用global或$GLOBALS |
脚本执行完才销毁 |
| 静态变量 | 函数内部,带static |
函数内直接使用 | 函数执行完保留值,下次调用继续用 |
一些术语:
-
作用域(Scope):变量能被访问的代码区域
-
超全局变量(Superglobal):如
$GLOBALS、$_POST、$_GET,随处可用 -
变量生命周期(Variable Lifetime):变量从创建到销毁的时间段
-
命名空间(Namespace):避免变量名冲突的机制,和
global配合使用效果更好
写代码时间长了会发现,变量作用域控制得好,代码出bug的概率会低很多。变量该藏就藏,该露就露,别图省事全搞成全局的——后面维护起来够你头疼的。