Skip to content

true / false / null 独立类型

概述

自 PHP 8.2 起,truefalsenull 可以作为独立的类型用于类型声明。在此之前,falsenull 只能出现在联合类型中(如 int|nullint|false)。true 则是全新的类型。

独立类型的引入使得 PHP 的类型系统更加完备,允许你精确地将参数、返回值或属性约束为只能是 truefalsenull

核心要点

  • truefalse 独立类型自 PHP 8.2 起可用。
  • null 独立类型自 PHP 8.2 起可用(之前只能通过 ?TT|null 使用)。
  • truefalse 不能同时出现在联合类型中,应使用 bool 代替。
  • 独立类型主要用于参数类型约束和返回值声明,提供更精确的类型安全。
  • :::

基础概念

什么是独立类型

在 PHP 8.2 之前,nullfalse 只能作为联合类型的一部分或通过 ? 语法糖使用。PHP 8.2 将它们提升为独立的一等类型,可以直接单独声明。

类型PHP 版本说明
bool全版本可为 truefalse
true8.2+只能为 true
false8.2+只能为 false
null8.2+只能为 null
?T7.1+等价于 T|null

独立类型与 bool / Null 的区别

声明接受的值场景
booltruefalse通用的布尔参数
truetrue确保参数必须为 true
falsefalse确保参数必须为 false
nullnull确保参数必须为 null
?stringstringnull可空的字符串

语法与代码示例

true 独立类型

php
<?php
declare(strict_types=1);

// 参数必须为 true
function enableFeature(bool $feature, true $confirm): void
{
    if ($feature) {
        echo "Feature enabled" . PHP_EOL;
    }
}

// 错误调用
enableFeature(true, false);   // TypeError: confirm 必须为 true

// 正确调用
enableFeature(true, true);     // OK

// 返回类型必须为 true
function alwaysReturnsTrue(): true
{
    return true;    // OK
}

// function alwaysReturnsTrue(): true
// {
//     return false; // TypeError: Return value must be true
// }

false 独立类型

php
<?php
declare(strict_types=1);

// 函数返回 false 表示失败
function isFailure(int $statusCode): false
{
    return false;  // OK
}

// 在联合类型中使用 false(PHP 8.0+ 的经典用法)
function strposWrapper(string $haystack, string $needle): int|false
{
    $result = strpos($haystack, $needle);
    return $result;  // 返回 int 或 false
}

// false 作为独立类型用于参数
function setStrictMode(false $disableStrict): void
{
    echo "Strict mode is disabled" . PHP_EOL;
}

null 独立类型

php
<?php
declare(strict_types=1);

// 参数必须为 null
function resetValue(null $reset): void
{
    echo "Value has been reset to null" . PHP_EOL;
}

// 错误调用
resetValue("hello");  // TypeError

// 正确调用
resetValue(null);      // OK

// 属性声明为 null
class Configuration
{
    public null $defaultValue = null;
    public string|null $optionalValue = null;
}

在联合类型中使用独立类型

php
<?php
declare(strict_types=1);

// 返回值只能是 string 或 false(PHP 8.0+ 就支持)
function findFile(string $filename): string|false
{
    if (file_exists($filename)) {
        return file_get_contents($filename);
    }
    return false;
}

// 返回值只能是 string 或 null
function getEnvVar(string $name): string|null
{
    return getenv($name);  // 返回 string 或 false,但类型声明只接受 string|null
}

// 返回值只能是 true 或 null
function checkPermission(string $role): true|null
{
    if ($role === 'admin') {
        return true;
    }
    return null;
}

详细说明

true 和 false 不能同时出现在联合类型中

PHP 不允许同时使用 truefalse,因为 true|false 等价于 bool,直接使用 bool 即可:

php
<?php
declare(strict_types=1);

// 错误:不能同时使用 true 和 false
function bad(bool $value): true|false {}  // Fatal Error

// 正确:使用 bool
function good(bool $value): bool {}

PHP 8.2 之前的限制

在 PHP 8.2 之前,以下类型声明是非法的:

php
<?php
declare(strict_types=1);

// PHP 8.2 之前的错误用法
function acceptsNull(null $value): void {}        // Fatal Error (PHP < 8.2)
function acceptsFalse(false $value): void {}       // Fatal Error (PHP < 8.2)
function returnsNull(): null {}                     // Fatal Error (PHP < 8.2)
function returnsFalse(): false {}                   // Fatal Error (PHP < 8.2)

// PHP 8.0+ 的等价写法
function acceptsNullFallback(?int $value): void {} // 只能通过 ?Type 实现
function returnsFalseFallback(): int|false {}       // 只能在联合类型中使用

独立类型的冗余检查

PHP 在编译时会检测类型冗余,避免简单的逻辑错误:

php
<?php
declare(strict_types=1);

// 以下均会报错
function bad1(): bool|true {}        // bool 已包含 true,true 冗余
function bad2(): bool|false {}       // bool 已包含 false,false 冗余
function bad3(): true|false {}        // 等价于 bool,应直接用 bool
function bad4(): int|null|true {}    // 如果使用 bool 则 true 冗余

独立类型与可空类型的对比

php
<?php
declare(strict_types=1);

// null 独立类型:只接受 null
function acceptsExactlyNull(null $value): void
{
    echo "Got null" . PHP_EOL;
}

// 可空类型:接受特定类型或 null
function acceptsStringOrNull(?string $value): void
{
    echo "Got: " . ($value ?? 'null') . PHP_EOL;
}

acceptsExactlyNull(null);       // OK
acceptsExactlyNull("hello");    // TypeError

acceptsStringOrNull(null);     // OK
acceptsStringOrNull("hello");  // OK
acceptsStringOrNull(42);       // TypeError

实战示例

使用 true 类型的布尔开关

php
<?php
declare(strict_types=1);

class FeatureFlag
{
    private array $flags = [
        'dark_mode' => false,
        'beta_api' => false,
    ];

    // 使用 true 参数确保只能开启,不能关闭
    public function enable(string $flag, true $confirmed): void
    {
        if (!isset($this->flags[$flag])) {
            throw new InvalidArgumentException("Unknown flag: {$flag}");
        }
        $this->flags[$flag] = true;
    }

    // 使用 false 参数确保只能关闭,不能开启
    public function disable(string $flag, false $confirmed): void
    {
        if (!isset($this->flags[$flag])) {
            throw new InvalidArgumentException("Unknown flag: {$flag}");
        }
        $this->flags[$flag] = false;
    }

    public function isEnabled(string $flag): bool
    {
        return $this->flags[$flag] ?? false;
    }
}

$features = new FeatureFlag();
$features->enable('dark_mode', true);
$features->disable('dark_mode', false);
// $features->enable('dark_mode', false);  // TypeError

使用 null 独立类型的重置机制

php
<?php
declare(strict_types=1);

class UserPreferences
{
    private array $settings = [
        'theme' => 'light',
        'language' => 'zh-CN',
        'timezone' => 'Asia/Shanghai',
    ];

    // null 独立类型表示"重置为默认"
    public function resetSetting(string $key, null $confirm): void
    {
        $defaults = [
            'theme' => 'light',
            'language' => 'zh-CN',
            'timezone' => 'Asia/Shanghai',
        ];

        $this->settings[$key] = $defaults[$key];
    }

    public function updateSetting(string $key, string $value): void
    {
        $this->settings[$key] = $value;
    }

    public function getSetting(string $key): string
    {
        return $this->settings[$key];
    }
}

$prefs = new UserPreferences();
$prefs->updateSetting('theme', 'dark');
$prefs->resetSetting('theme', null);

使用 false 作为返回值标记失败

php
<?php
declare(strict_types=1);

interface RepositoryInterface
{
    /**
     * 查找记录
     * @return array 成功时返回数据
     * @return false 失败时返回 false
     */
    public function findById(int $id): array|false;
}

class UserRepository implements RepositoryInterface
{
    public function findById(int $id): array|false
    {
        $result = $this->query("SELECT * FROM users WHERE id = ?", [$id]);

        if ($result === null) {
            return false;
        }

        return $result;
    }

    private function query(string $sql, array $params): ?array
    {
        // 模拟数据库查询
        return null;
    }
}

注意事项

独立类型的适用场景

独立类型 truefalsenull 并不适用于所有场景。它们最适合以下情况:

场景是否适合原因
布尔参数需要确保只能是 true适合防止误传 false
函数返回值用于标记成功/失败适合false 明确表示失败
需要将参数约束为仅 null较少使用通常用 ?Type 更合适
通用的布尔参数不适合应使用 bool
可空参数不适合应使用 ?Type

PHP 版本兼容性

php
<?php
declare(strict_types=1);

// PHP 8.0+ 可用:false 在联合类型中
function find(): string|false {}

// PHP 8.2+ 可用:false/null/true 作为独立类型
function acceptTrue(true $v): void {}
function acceptFalse(false $v): void {}
function acceptNull(null $v): void {}
function returnTrue(): true {}
function returnFalse(): false {}
function returnNull(): null {}

最佳实践

  1. 在联合类型中优先使用 false 而非 null 表示失败:PHP 内置函数(如 strposfile_get_contents)广泛使用 false 表示失败,保持一致性。

  2. 谨慎使用 truenull 独立类型:这些类型使用场景相对有限,过度使用可能降低代码可读性。

  3. true 类型适合"确认"参数:当布尔参数需要确保只能是 true 时(如操作确认、特性启用),使用 true 类型可以防止误传 false

  4. 不要用 true|false 替代 booltrue|false 是非法的,PHP 会报错。直接使用 bool 类型。

  5. 在联合类型中善用 falsestring|falseint|false 等联合类型在表示"成功返回值或失败标记"时非常实用。

  6. 配合严格模式使用:独立类型在 declare(strict_types=1) 下更加可靠,确保类型安全。

参考链接