编程

PHP 8.4: exit/die 从语言构造修改为函数

106 2024-12-15 17:34:00

exit 关键词及其别名 die 是输出消息并终止当前脚本的语言构造。在 CLI 应用中,exit/die 可用于通过给定退出码终止应用。

有些语言构造,如 requireincludeechoexit,与 PHP 函数类似,但它们有自己的标记和功能,不一定有返回值,也不需要用括号调用。

由于 exitdie 是语言构造,它允许以各种方式调用它。它不需要括号,并接受一个字符串或 int 值,这些值要么打印到 STDOUT(如果是字符串),要么用作退出码(如果是 int):

exit; // Allowed
exit(); // Allowed
exit(1); // Allowed
exit("Fatal error, exiting"); // Allowed

在 PHP 8.4 之前,它的可选参数接收一个 string 或一个 int 值,不过并不遵循同样的强制类型转换或者严格类型行为。

declare(strict_types=1);

exit([]);
Warning: Array to string conversion in ... on line ...
Array

在 PHP 8.4 中,exitdie 被声明为 PHP 函数。它们具有特殊的处理方式,允许在没有括号的情况下调用它们,以确保与旧 PHP 应用的向后兼容性。

exitdie 函数摘要

function exit(string|int $status = 0): never {}

function die(string|int $status = 0): never {}

函数 die 等价于 exit 函数。这两个函数都在全局命名空间中进行声明,返回类型都为 never

未修改:不带括号调用 exitdie

为确保向后兼容性,exitdie 函数仍然可用不使用括号进行调用。这样的调用不会发出任何弃用通知。T

exit; // Allowed
die; // Allowed

未修改:exitdie 不能使用 disable_functions INI 指令禁用

新增的 exitdie 函数不能使用 disable_functions INI 指令禁用。这么做会发出一个 PHP 警告,且该函数保持启用:

[PHP]
disable_functions=exit,die
Warning: Cannot disable function exit()
Warning: Cannot disable function die()

未修改:exitdie 不可用于函数名、类名、常量名和 goto标签

exitdie 不允许是函数名或常量名,即使在命名空间内也是如此。此外,exitdie 不能用作 goto 的标签。

以下所有代码在所有 PHP 版本(包括 PHP 8.4 及更高版本)中都会导致语法错误。

function exit() {}

namespace Test;
function exit() {}
Parse error: syntax error, unexpected token "exit", expecting "("
const die = 42;
const EXIT = 42;
Parse error: syntax error, unexpected token "exit", expecting identifier

仍然可以使用 define 来声明具有 exitdie 名称的常量。但是,请注意,尝试使用常量将调用 dieexit,而不是检索常量值。

exit:
echo "Called";
Parse error: syntax error, unexpected token ":"

未修改:exitdie 可用作枚举成员、类常量、方法和属性

exitdie 可用作类常量名、方法名和属性名。以下代码在所有 PHP 版本,包括 PHP 8.4 及更高版本,都是有效的。此外,因为枚举内部继承了 PHP 类结构 exitdie 也可以作为有效的枚举成员名使用:

class Test {
    public int $exit = 442;
    public int $die = 116;

    public const int exit = 42;
    public const int die = 16;

    public function exit() {
        return self::exit;
    }

    public function die() {
        return self::die;
    }
}

$c = new Test();
echo $c->exit(); // 42
echo $c->die(); // 16
echo $c->exit; // 442
echo $c->die; // 116
echo Test::exit; // 42
echo Test::die; // 16

类型处理变更

因为 exitdie 在 PHP 8.4 及更高版本中是 PHP 函数,所以它们现在遵循其他 PHP 函数遵循的标准类型处理。

ArgumentCountError on additional parameters

之前,传递超过一个参数给 exit/die 会导致语法错误。在 PHP 8.4 上,则会抛出 ArgumentCountError 异常。

exit(255, "foobar");
ArgumentCountError: exit() expects at most 1 argument, 2 given

strict_types 时的标准类型转换

与其他 PHP 函数的工作方式类似,exitdie 现在也遵循相同的类型转换/强制规则。这会影响向后兼容性,但可以说是朝着更正确的方向发展。

请注意:

  • 在 PHP 8.4 之前,exit(true) 被强制转换为 exit("1"),因此 “1” 被打印到 STDOUT,退出码为 0(无错误)。在 PHP 8.4 及更高版本中,这现在被解析为 exit(1),退出码为 1(错误)。
  • 传入 float 值将触发将浮点型转换为 int 的隐式转换,会触发精度弃用消息。
  • 传入 null 将触发弃用通知因为 exit/die 只接收 string|int

strict_types 生效时将抛出 TypeError 异常

strict_types 生效时,传入不是 stringint 将抛出 TypeError 异常:

declare(strict_types=1);

exit(null);
TypeError: exit(): Argument #1 ($status) must be of type string|int, null given

exitdie 可被调用(callable)

因为 exitdie 是 PHP 函数,它们现在可以被用作标准的 PHP callable。

在 PHP 8.3 及之前的版本中,以下代码会失败,因为 exit 在这些版本中未被声明为 callable 函数。

$callable = 'exit';
$status = "My success message";
$callable($status);
$callable = exit(...);
$status = "My success message";
$callable($status);

上例使用了 first-class callable 语法。

向后兼容性影响

exitdie 现在是 PHP 函数。然而,这一变化在很大程度上与旧的 PHP 版本向后兼容,因为 exitdie 仍然不允许作为类、常量和函数名,并且继续允许作为类常量、属性和方法名。
只有 PHP 8.4 及更高版本支持使用 exitdie作为可调用对象。

由于 exitdie 是旧 PHP 版本中的语言构造,因此不可能(也不需要)对这些函数进行 polyfill。