Skip to content

isset / unset / empty

概述

isset()unset()empty() 是 PHP 中处理变量的三个核心语言结构(不是函数)。它们用于检查变量是否存在、销毁变量以及检查变量是否为"空值"。理解它们的区别和正确用法是编写健壮 PHP 代码的基础。

PHP 版本说明

  • isset()empty() 是语言结构,不是函数,不能用可变函数调用
  • PHP 7.0 引入 ??(null 合并运算符),可以部分替代 isset() 检查
  • PHP 7.4 引入 ??=(null 合并赋值运算符)
  • isset() 支持多参数自 PHP 5 起可用

基础概念

三个语言结构对比

语言结构功能对未定义变量对 null返回值类型
isset($var)检查变量是否已设置且非 null返回 false(不报错)返回 falsebool
unset($var)销毁变量不报错销毁变量void
empty($var)检查变量是否为空返回 true(不报错)返回 truebool

语言结构 vs 函数

issetunsetempty 是语言结构(language construct),不是函数。它们不能被可变函数调用:$func = 'isset'; $func($var); 会导致错误。

语法与代码

isset() 详解

isset() 检查变量是否已设置且不为 null。如果变量存在且值不为 null,返回 true,否则返回 false

php
<?php

declare(strict_types=1);

// 已定义且非 null
$name = 'Alice';
echo isset($name) ? 'set' : 'not set'; // set

// 已定义但为 null
$age = null;
echo isset($age) ? 'set' : 'not set'; // not set

// 未定义的变量
echo isset($undefined) ? 'set' : 'not set'; // not set(不报错)

// 检查数组键
$data = ['name' => 'Alice', 'email' => 'alice@example.com'];
echo isset($data['name']) ? 'set' : 'not set'; // set
echo isset($data['phone']) ? 'set' : 'not set'; // not set(不报错)

// 多参数 isset(全部设置才返回 true)
$a = 1;
$b = 2;
$c = null;
var_dump(isset($a, $b));     // true
var_dump(isset($a, $b, $c)); // false($c 为 null)

isset 与直接比较

isset($var) 等价于 array_key_exists('key', $array) && $array['key'] !== null。对于数组,如果需要区分"键不存在"和"值为 null",应使用 array_key_exists()

unset() 详解

unset() 销毁指定的变量,使其不再存在。

php
<?php

declare(strict_types=1);

// 销毁变量
$name = 'Alice';
echo $name . "\n"; // Alice

unset($name);
echo isset($name) ? 'set' : 'not set'; // not set
// echo $name; // Undefined variable

// 销毁数组元素
$user = ['name' => 'Alice', 'age' => 30, 'email' => 'alice@example.com'];
unset($user['email']);
print_r($user);
// Array ( [name] => Alice [age] => 30 )

// 销毁多个变量
$a = 1;
$b = 2;
$c = 3;
unset($a, $b, $c);

// unset 对引用的影响
$x = 'hello';
$ref = &$x; // $ref 是 $x 的引用
unset($x);   // 只销毁 $x,不影响 $ref
echo $ref . "\n"; // hello($ref 仍然存在)

// 销毁全局变量(在函数内部)
$globalVar = 'I am global';

function destroyGlobal(): void
{
    // global $globalVar;
    // unset($globalVar); // 只销毁局部引用,不影响全局变量
    unset($GLOBALS['globalVar']); // 销毁真正的全局变量
}

destroyGlobal();
echo isset($globalVar) ? 'exists' : 'destroyed'; // destroyed

empty() 详解

empty() 检查变量是否被视为"空"。以下值被认为是空的:

  • ''(空字符串)
  • 0(整数 0)
  • 0.0(浮点数 0)
  • '0'(字符串 '0')
  • null
  • false
  • [](空数组)
  • $undefinedVar(未定义变量)
php
<?php

declare(strict_types=1);

// 被视为空的值
$emptyValues = [
    '' => 'empty string',
    0 => 'integer zero',
    0.0 => 'float zero',
    '0' => 'string zero',
    null => 'null',
    false => 'false',
    [] => 'empty array',
];

foreach ($emptyValues as $value => $description) {
    echo empty($value) ? "[EMPTY] {$description}\n" : "[NOT EMPTY] {$description}\n";
}

// 不被视为空的值
$nonEmptyValues = [
    'hello' => 'non-empty string',
    1 => 'non-zero integer',
    true => 'true',
    [0] => 'non-empty array',
    'false' => 'string "false"',
];

foreach ($nonEmptyValues as $value => $description) {
    echo empty($value) ? "[EMPTY] {$description}\n" : "[NOT EMPTY] {$description}\n";
}

// empty 不会产生 Undefined variable 警告
echo empty($undefinedVar) ? 'empty' : 'not empty'; // empty(安全)

'0' 被视为空

字符串 '0'empty() 视为空值,这在处理表单输入和 API 参数时需要特别注意。建议使用更精确的比较来判断。

与 null 比较的区别

php
<?php

declare(strict_types=1);

$var = null;

// isset vs === null
var_dump(isset($var));      // false
var_dump($var === null);    // true
var_dump($var ?? 'default'); // 'default'

// 未定义的变量
// var_dump($undefined === null); // Undefined variable(报错)
var_dump(isset($undefined));     // false(不报错)
var_dump($undefined ?? 'default'); // 'default'(不报错)

// empty vs === null
$zero = 0;
var_dump(empty($zero));       // true(0 被视为空)
var_dump($zero === null);     // false(0 不是 null)
var_dump($zero ?? 'default'); // 0(0 不是 null,所以返回 0)

// 关键区别总结
// isset($var)       → 变量存在且不为 null
// $var === null     → 变量值是 null(变量必须存在)
// empty($var)       → 变量为假值(包括 0, '', '0', false, null, [], 未定义)
// $var ?? 'default' → 变量存在且不为 null,否则返回默认值

$var ?? 'default' 替代 isset

PHP 7.0+ 的 null 合并运算符 ??isset() 检查的简洁替代。

php
<?php

declare(strict_types=1);

// 旧写法
$name = isset($_GET['name']) ? $_GET['name'] : 'Anonymous';

// 新写法(PHP 7.0+)
$name = $_GET['name'] ?? 'Anonymous';

// 多层嵌套
// 旧写法
$user = isset($data['user']) ? (isset($data['user']['name']) ? $data['user']['name'] : 'Unknown') : 'Unknown';

// 新写法
$user = $data['user']['name'] ?? 'Unknown'; // 如果 $data['user'] 不存在也不会报错

// null 合并赋值(PHP 7.4+)
$config = [];
$config['debug'] ??= false;    // 相当于: $config['debug'] = $config['debug'] ?? false
$config['cache'] ??= true;
$config['timeout'] ??= 30;

print_r($config);
// Array ( [debug] => false [cache] => true [timeout] => 30 )

详细说明

isset 的短路行为

isset() 是短路运算:如果第一个参数就不满足条件,不会继续检查后续参数。

php
<?php

declare(strict_types=1);

$data = ['user' => null];

// isset 短路:$data['user'] 为 null,不会访问 $data['user']['name']
var_dump(isset($data['user'], $data['user']['name'])); // false

// 如果 $data['user'] 不为 null,才会检查第二个参数
$data['user'] = ['name' => 'Alice'];
var_dump(isset($data['user'], $data['user']['name'])); // true

// 空合并运算符也有短路行为
$result = $data['user']['name'] ?? $data['user']['email'] ?? 'Unknown';
echo $result . "\n"; // Alice

数组操作中的 isset vs array_key_exists

php
<?php

declare(strict_types=1);

$arr = ['a' => 1, 'b' => null, 'c' => 0];

// isset vs array_key_exists
var_dump(isset($arr['a']));                // true
var_dump(array_key_exists('a', $arr));     // true

var_dump(isset($arr['b']));                // false(值为 null)
var_dump(array_key_exists('b', $arr));     // true(键存在)

var_dump(isset($arr['d']));                // false(键不存在)
var_dump(array_key_exists('d', $arr));     // false(键不存在)

// PHP 8.0+ 可以使用 $arr['key'] ?? null 替代 array_key_exists(但语义略有不同)
var_dump($arr['b'] ?? null); // null(键存在但值为 null,返回 null,无法区分)
var_dump($arr['d'] ?? null); // null(键不存在,同样返回 null)

选择建议

  • 需要区分"键不存在"和"值为 null"时,使用 array_key_exists()
  • 只关心值是否可用(非 null)时,使用 isset()??

实战示例

安全的请求数据获取

php
<?php

declare(strict_types=1);

function getRequestParam(array $params, string $key, mixed $default = null): mixed
{
    return $params[$key] ?? $default;
}

function getIntParam(array $params, string $key, int $default = 0): int
{
    $value = $params[$key] ?? null;

    if ($value === null) {
        return $default;
    }

    return is_numeric($value) ? (int) $value : $default;
}

function getStringParam(array $params, string $key, string $default = ''): string
{
    $value = $params[$key] ?? null;

    if ($value === null) {
        return $default;
    }

    return is_string($value) ? trim($value) : $default;
}

// 模拟请求参数
$_GET = ['page' => '2', 'search' => '  php  ', 'sort' => ''];

$page = getIntParam($_GET, 'page', 1);
$search = getStringParam($_GET, 'search', '');
$sort = getStringParam($_GET, 'sort', 'date');
$limit = getIntParam($_GET, 'limit', 20);

echo "page: {$page}, search: '{$search}', sort: '{$sort}', limit: {$limit}\n";
// page: 2, search: 'php', sort: 'date', limit: 20

条件性清理变量

php
<?php

declare(strict_types=1);

function processLargeData(array &$data): void
{
    $result = [];

    foreach ($data as $key => $value) {
        $result[$key] = processItem($value);
    }

    // 清理原始数据释放内存
    $data = [];

    // 处理完成,可以 unset 临时变量
    unset($result);
}

function processItem(mixed $item): mixed
{
    return $item;
}

$largeData = array_fill(0, 100000, 'data');
processLargeData($largeData);
echo empty($largeData) ? 'cleared' : 'still has data'; // still has data(函数内 unset 只影响局部引用)

注意事项

常见陷阱

  1. empty('0') 返回 true
php
<?php

declare(strict_types=1);

$statusCode = '0';

// 错误:empty('0') 返回 true
if (empty($statusCode)) {
    echo "Status is empty\n"; // 实际执行了这里
}

// 正确:使用精确比较
if ($statusCode === '') {
    echo "Status is empty string\n";
}
  1. unset 不影响引用链中的其他变量(只解除当前变量)
php
<?php

declare(strict_types=1);

$a = 'hello';
$b = &$a;
$c = &$a;

unset($a);
// $b 和 $c 仍然存在且值为 'hello'
echo $b . "\n"; // hello
echo $c . "\n"; // hello
  1. 函数参数默认不会检查 isset
php
<?php

declare(strict_types=1);

function process(string $name): void
{
    // 如果传入未定义的变量会报错
    echo $name . "\n";
}

// $undefined 未定义
// process($undefined); // Undefined variable

// 安全方式
$undefined ??= 'default';
process($undefined ?? 'default');

最佳实践

1. 使用 ?? 替代 isset + 三元运算符

php
<?php

declare(strict_types=1);

// 推荐
$name = $data['name'] ?? 'Anonymous';
$age = $data['age'] ?? 0;
$active = $data['active'] ?? true;

// 不推荐
$name = isset($data['name']) ? $data['name'] : 'Anonymous';

2. empty 要谨慎使用,优先精确判断

php
<?php

declare(strict_types=1);

// 不推荐:empty 太宽泛
if (!empty($value)) { ... }

// 推荐:精确判断
if ($value !== null && $value !== '') { ... }
if ($value !== '' && $value !== 0) { ... }

3. 及时释放不再需要的变量

php
<?php

declare(strict_types=1);

function processFile(string $path): array
{
    $content = file_get_contents($path);
    $result = json_decode($content, true);
    unset($content); // 处理完后及时释放

    return $result;
}

参考链接