
PHP 团队发布了开源脚本语言 PHP 8.5 版本,该语言为包括使用 WordPress CMS 的网站在内的众多 Web 应用提供支持。
PHP 8.5 于 11 月发布,标志着 PHP 社区承诺每年发布重大更新的第二年,并且每个版本都将获得两年的积极支持。
虽然 8.5 是全新的版本,但我们已在年度 PHP 基准测试中对其进行了全面评估,测试涵盖了各种流行的 CMS 平台和框架。
如果您计划将 PHP 应用程序迁移到 8.5 版本,则需要了解此最新版本中的更改。这包括您可以利用的新功能(可用于改进代码)以及 PHP 开发人员即将移除的旧功能。
以下是我们认为新版本的主要亮点:
PHP 8.5中的新功能和改进
让我们从 PHP 代码库的新增内容开始。这些变更通常以征求意见稿 (RFC) 的形式出现,最终可能会获得批准并纳入未来的 PHP 版本。
以下介绍的新功能是 PHP 8.5 版本中最受关注的几个方面。
使用管道运算符链接函数调用
新的管道运算符 (|>) 以一种 JavaScript 程序员会感到似曾相识的方式链接函数调用。管道从左到右运行,每一步都传递一个值。
在之前的 PHP 版本中,程序员可能需要通过嵌套函数或逐个执行函数调用并检查每一步的返回值来完成类似的任务。
以下是一个使用新管道运算符的简单示例:
$text = ' New-in-php-8.4 ';
$result = $text
|> trim(...)
|> (fn($str) => str_replace('4', '5', $str))
|> (fn($str) => str_replace('-', ' ', $str))
|> strtoupper(...);
var_dump($result);
// string(14) "NEW IN PHP 8.5"
(请注意,我们使用的是 PHP 8.1 中引入的一等可调用语法 (...),该语法用于调用 trim() 和 strtoupper() 函数。)
上面的管道链可以写在一行中,但可读性正是这个新运算符的优势之一。
上述操作等价于将这些操作(按相反顺序)嵌套在一起,如下所示:
$text = " New-in-php-8.4 ";
$result = strtoupper(
str_replace(‘-, ' ',
str_replace('4', '5',
trim($text)
)
)
);
或者,程序员可能在早期的 PHP 版本中像这样完成这项任务:
$text = " New-in-php-8.4 ";
$result = trim($text);
$result = str_replace('4', '5', $result);
$result = str_replace(‘-, ' ', $result);
$result = strtoupper($result);
使用新的URI扩展解析URL
URL(也称为 URI,更严谨的说法)是 Web 导航的关键,但 PHP 4 版本以来内置的 parse_url() 函数在处理格式错误的输入时存在问题,这可能导致在尝试操作或验证网站地址时出现错误。
为了改进 URL 解析,PHP 8.5 引入了 uriparser 和 Lexbor 库,分别支持 RFC 3986 和 WHATWG URL 标准。
您可以通过以下方式使用新的 URI 扩展来调用 `uriparser` 库:
$uri = new Uri\Rfc3986\Uri("https://www.dianavpn.com/blog/what-is-a-vpn/");
echo $uri->getScheme(); // https
echo $uri->getHost(); // www.dianavpn.com
echo $uri->getPath(); // /blog/what-is-a-vpn
或者,您可以选择 Lexbor WHATWG URL 库,如下所示:
$uri = new Uri\WagWg\Url("https://www.dianavpn.com/blog/what-is-a-vpn/");
echo $uri->getScheme(); // https
echo $uri->getUnicodeHost(); // www.dianavpn.com
echo $uri->getAsciiHost(); // www.dianavpn.com
echo $uri->getPath(); // /blog/what-is-a-vpn
以上示例最为基础。PHP 8.5 中 URI 扩展所代表的两个库功能相同,但也存在显著差异。
一个重要的区别是,RFC 3986 库同时支持 URI 的“原始”和“规范化解码”表示形式。这在处理百分比编码的输入和输出时非常有用。例如,在浏览器中,以下两个 URI 完全相同:
在之前的 PHP 版本中,您可能需要使用 rawurldecode() 和 rawurllencode() 函数(它们也符合 RFC 3986 标准),但新的扩展程序开箱即用,可以处理 URI 的所有组成部分,无论它们是否经过编码。
以下是一些直接摘自新解析 API 背后的 RFC 文档的示例:
$uri = new Uri\Rfc3986\Uri("https://%61pple:p%61ss@ex%61mple.com/foob%61r?%61bc=%61bc");
echo $uri->getRawUserInfo(); // %61pple:p%61ss
echo $uri->getUserInfo(); // apple:pass
echo $uri->getRawUsername(); // %61pple
echo $uri->getUsername(); // apple
echo $uri->getRawPassword(); // p%61ss
echo $uri->getPassword(); // pass
echo $uri->getRawHost(); // ex%61mple.com
echo $uri->getHost(); // example.com
echo $uri->getRawPath(); // /foob%61r
echo $uri->getPath(); // /foobar
echo $uri->getRawQuery(); // %61bc=%61bc
echo $uri->getQuery(); // abc=abc
使用带有新扩展的 WHATWG URL 库时,所有 URI 都被视为“原始”URI,因此没有单独的函数集来支持其他格式。但该库可以在 URI 中常见的 ASCII 和 Unicode 字符之间进行转换。
使用新的max_memory_limit INI指令严格控制内存
人们常说,能力越大,责任越大。如果这种权力包括选择 PHP 应用程序可以使用的服务器内存量,那么当进程消耗的内存超过可用内存时,应用程序崩溃就可能需要您承担责任。
典型的 PHP 安装包含一个 php.ini 文件,其中包含配置信息,其中包括一个指令,用于指定任何 PHP 进程(或线程)的内存消耗限制。一个常见的 128 MB 内存限制的 INI 指令如下所示:
// php.ini memory_limit 128M
在某些托管平台上,PHP 应用程序的开发人员可以使用代码中的 ini_set() 函数动态地覆盖 memory_limit:
ini_set(‘memory_limit’, ‘256M’); // Start code that requires up to 256 MB of memory
您还可以向函数传递值 -1,例如 ini_set('memory_limit', '-1'),以完全取消内存限制。
对于不熟悉应用程序运行服务器内存配置的开发人员来说,覆盖 INI 指令的内存限制可能存在风险。如果一个或多个 PHP 线程尝试消耗超过总内存池的内存,则可能导致应用程序在运行时崩溃且不会发出警告。
PHP 8.5 添加了 max_memory_limit INI 指令,即使在开发人员可以使用 init_set() 函数调整代码内存使用的情况下,该指令也起到了硬性限制的作用。
以下是 PHP 8.5 安装的 php.ini 文件中的示例条目:
// php.ini max_memory_limit 256M memory_limit 128M
当 max_memory_limit 设置为 256 MB 时,我们的 PHP 代码会执行以下操作:
ini_set('memory_limit', '256M'); // This is OK
ini_set('memory_limit', '512M'); // Fail with warning
ini_set('memory_limit', '-1'); // Fail with warning
尝试将内存限制设置为 512 MB(或无限制)以上值将不会成功。PHP 会将内存限制设置为 php.ini 文件中 max_memory_limit 的值,并发出警告。(警告信息可能会显示在屏幕上并被记录,具体取决于 PHP 安装的错误报告设置。)
对于 PHP 8.5 开发人员来说,明智的做法是使用 ini_get() 函数来查看是否已定义新的最大限制,例如 ini_get('max_memory_limit'),然后根据返回值进行调整。对于 8.5 之前的 PHP 版本,该调用会安全地返回 false。
获取数组中的第一个或最后一个值
如果你之前认为 PHP 已经提供了读取数组中第一个或最后一个元素的值的函数,请举手。
事实上,它并没有。但从 PHP 7.3 开始,它提供了获取数组中第一个和最后一个键的函数。因此,要查找第一个和最后一个值,你可以使用 array_key_first() 或 array_key_last() 函数,然后使用返回的键来引用你要查找的值:
$array = ["One", "Two", "Three"]; echo $array[array_key_first($array)]; // "One"
PHP 8.5 简化了这一步骤,允许您使用新的 array_first() 和 array_last() 函数直接获取数组中的值。
一切都很简单:
$array = ["One", "Two", "Three"]; echo array_first($array); // "One" echo array_last($array); // "Three" echo array_last([]); // null
如上所示,空数组会返回 null,但这本身并不能确认整个数组为空,因为数组中的某个值可能为null:
echo array_last([1, 2, null]); // null
提醒您使用函数的返回值
PHP 5.8 新增了一个 #[\NoDiscard] 属性,用于指示函数的返回值可能至关重要。PHP 会检查返回值是否被以某种方式使用,如果没有,则会触发警告。
一个简单的例子:
#[\NoDiscard("this message property will be appended to the built-in warning.")]
function foo(): string {
return 'bar';
}
// Warning:
// The return value of function foo() is expected to be consumed,
// this message property will be appended to the built-in warning.
foo();
// This will not trigger a warning:
$result = foo();
// Also satisfactory is the (void) cast:
(void) foo();
在上面的示例中,定义函数的返回值在第一次运行时完全没有被使用,从而触发了警告。但是,当将其赋值给变量 $result 或强制转换为 void 类型时,该值被认为已被使用。
PHP 8.5 中新增的这项功能对应的 RFC 文档的作者们描述了比上述简单示例更具说服力的用法。其中一个场景是关键函数,其错误报告比简单的通过/失败更复杂,而通过函数的返回值来传达错误信息是最佳方式。
其他与属性相关的增强功能
除了新增的 #[\NoDiscard] 属性之外,新版本中对属性元数据功能的其他增强功能还包括:
- 属性现在可以指向常量。
#[\Override]属性现在可以应用于属性。#[\Deprecated]属性可以用于特性和常量。- 可以使用新的
#[\DelayedTargetValidation]属性来抑制在无效目标上使用的核心和扩展属性的编译时错误。
PHP 8.5中的弃用和移除
每个 PHP 版本发布时都会列出一些功能,这些功能将被标记为在未来的版本中移除。在代码中使用已弃用的功能会触发警告。当这些功能最终从 PHP 中移除时,继续使用可能会导致致命错误。
以下是 PHP 8.5 中一些值得注意的已弃用或移除的功能:
- 反引号运算符作为
shell_exec()的别名已被弃用。 - 非规范类型转换名称
(boolean)、(integer)、(double)和(binary)已被弃用。请改用(bool)、(int)、(float)和(string)。 - disable_classes INI 设置已被移除,因为它会导致各种引擎假设被破坏。
- 使用分号而不是冒号结束
case语句已被弃用。 - 现在已弃用将 null 用作数组偏移量或在调用
array_key_exists()时使用 null。请改用空字符串。 - 现在不能再在
class_alias()中使用array和callable作为类别名。 __sleep()和__wakeup()魔术方法已被软弃用。请改用__serialize()和__unserialize()魔术方法。- 现在将 NaN 强制转换为其他类型时会发出警告。
- 现在使用
[]或list()解构非数组值(null 除外)时会发出警告。 - 现在将浮点数(或看起来像浮点数的字符串)强制转换为 int 类型时,如果它们不能表示为
int,则会发出警告。
小结
以上是 PHP 8.5 版本的主要更新内容。我们相信新的管道运算符和改进的 URI 解析功能将受到开发者的欢迎。或许连新的 array_first() 和 array_last() 函数也包含在内,我们原本以为它们早就存在了。
但任何新的 PHP 版本都包含数百项更改。您可以在 PHP 官方 GitHub 代码库中找到 PHP 8.5 更新的完整列表。


评论留言