2024 年 PHP 日本大会

新增功能

标量类型声明

标量类型声明有两种形式:强制(默认)和严格。现在可以强制执行参数的以下类型(强制或严格):字符串(string)、整数(int)、浮点数(float)和布尔值(bool)。它们增强了 PHP 5 中引入的其他类型:类名、接口、arraycallable

<?php
// 强制模式
function sumOfInts(int ...$ints)
{
return
array_sum($ints);
}

var_dump(sumOfInts(2, '3', 4.1));

以上示例将输出

int(9)

要启用严格模式,必须在文件的顶部放置单个declare 指令。这意味着标量类型的严格性是在每个文件的基础上配置的。此指令不仅影响参数的类型声明,还影响函数的返回类型(参见返回类型声明、内置 PHP 函数和来自已加载扩展的函数。

标量类型声明的完整文档和示例可以在类型声明参考中找到。

返回类型声明

PHP 7 添加了对返回类型声明的支持。与参数类型声明类似,返回类型声明指定将从函数返回的值的类型。返回类型声明可以使用与参数类型声明相同的类型

<?php

function arraysSum(array ...$arrays): array
{
return
array_map(function(array $array): int {
return
array_sum($array);
},
$arrays);
}

print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));

以上示例将输出

Array
(
    [0] => 6
    [1] => 15
    [2] => 24
)

返回类型声明的完整文档和示例可以在返回类型声明参考中找到。

空值合并运算符

空值合并运算符(??)作为语法糖添加,用于需要将三元运算符与isset()结合使用的常见情况。如果它的第一个操作数存在且不为null,则返回第一个操作数;否则返回第二个操作数。

<?php
// 获取 $_GET['user'] 的值,如果不存在则返回 'nobody'
//
$username = $_GET['user'] ?? 'nobody';
// 这等效于:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// 可以链接合并:这将返回从 $_GET['user']、$_POST['user'] 和
// 'nobody' 中定义的第一个值。
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

太空船运算符

太空船运算符用于比较两个表达式。当$a分别小于、等于或大于$b时,它返回-1、0或1。比较根据 PHP 通常的类型比较规则执行。

<?php
// 整数
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1

// 浮点数
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1

// 字符串
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
?>

使用define()定义常量数组

现在可以使用define()定义Array常量。在 PHP 5.6 中,它们只能使用const定义。

<?php
define
('ANIMALS', [
'dog',
'cat',
'bird'
]);

echo
ANIMALS[1]; // 输出 "cat"
?>

匿名类

通过new class添加了对匿名类的支持。这些可以用在完整类定义的地方,用于临时对象。

<?php
interface Logger {
public function
log(string $msg);
}

class
Application {
private
$logger;

public function
getLogger(): Logger {
return
$this->logger;
}

public function
setLogger(Logger $logger) {
$this->logger = $logger;
}
}

$app = new Application;
$app->setLogger(new class implements Logger {
public function
log(string $msg) {
echo
$msg;
}
});

var_dump($app->getLogger());
?>

以上示例将输出

object(class@anonymous)#2 (0) {
}

完整的文档可以在匿名类参考中找到。

Unicode代码点转义语法

此语法接受十六进制形式的Unicode代码点,并将该代码点以UTF-8格式输出到双引号字符串或heredoc中。任何有效的代码点都被接受,可以省略前导0。

<?php

echo "\u{aa}", PHP_EOL;
echo
"\u{0000aa}", PHP_EOL;

echo
"\u{9999}", PHP_EOL;

echo <<<EOT
\u{01f418}
EOT;

?>

以上示例将输出

ª
ª (same as before but with optional leading 0's)
香

Closure::call()

Closure::call() 是一种更高效的简写方法,用于临时将对象作用域绑定到闭包并调用它。

<?php
class A {private $x = 1;}

// PHP 7之前的代码
$getX = function() {return $this->x;};
$getXCB = $getX->bindTo(new A, 'A'); // 中间闭包
echo $getXCB();

// PHP 7及以上代码
$getX = function() {return $this->x;};
echo
$getX->call(new A);

以上示例将输出

1
1

过滤后的 unserialize()

此功能旨在在对不可信数据进行反序列化时提供更好的安全性。它通过允许开发人员将允许反序列化的类列入白名单来防止可能的代码注入。

<?php

// 将所有对象转换为 __PHP_Incomplete_Class 对象
$data = unserialize($foo, ["allowed_classes" => false]);

// 将所有对象转换为 __PHP_Incomplete_Class 对象,除了 MyClass 和 MyClass2 的对象
$data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]]);

// 默认行为(与省略第二个参数相同),接受所有类
$data = unserialize($foo, ["allowed_classes" => true]);

IntlChar

新的IntlChar类旨在公开更多的ICU功能。该类本身定义了许多静态方法和常量,可用于操作Unicode字符。

<?php

printf
('%x', IntlChar::CODEPOINT_MAX);
echo
IntlChar::charName('@');
var_dump(IntlChar::ispunct('!'));

以上示例将输出

10ffff
COMMERCIAL AT
bool(true)

要使用此类,必须安装Intl扩展。

断言

断言是对旧的assert()函数向后兼容的增强。它们允许在生产代码中进行零成本断言,并在断言失败时提供抛出自定义异常的能力。

虽然为了兼容性而继续维护旧的API,但assert()现在是一个语言结构,允许第一个参数为表达式,而不仅仅是一个字符串来评估或一个布尔值来测试。

<?php
ini_set
('assert.exception', 1);

class
CustomError extends AssertionError {}

assert(false, new CustomError('Some error message'));
?>

以上示例将输出

Fatal error: Uncaught CustomError: Some error message

有关此功能的完整详细信息,包括如何在开发和生产环境中配置它,可以在assert()语言结构的手册页上找到。

分组 `use` 声明

从同一个命名空间导入的类、函数和常量现在可以组合在一个use语句中。

<?php
// PHP 7之前的代码
use some\namespace\ClassA;
use
some\namespace\ClassB;
use
some\namespace\ClassC as C;

use function
some\namespace\fn_a;
use function
some\namespace\fn_b;
use function
some\namespace\fn_c;

use const
some\namespace\ConstA;
use const
some\namespace\ConstB;
use const
some\namespace\ConstC;

// PHP 7及以上代码
use some\namespace\{ClassA, ClassB, ClassC as C};
use function
some\namespace\{fn_a, fn_b, fn_c};
use const
some\namespace\{ConstA, ConstB, ConstC};
?>

生成器返回值表达式

此特性建立在 PHP 5.5 中引入的生成器功能之上。它允许在生成器中使用 return 语句,以便返回最终表达式(不允许按引用返回)。可以使用新的 Generator::getReturn() 方法获取此值,该方法只有在生成器完成产出值后才能使用。

<?php

$gen
= (function() {
yield
1;
yield
2;

return
3;
})();

foreach (
$gen as $val) {
echo
$val, PHP_EOL;
}

echo
$gen->getReturn(), PHP_EOL;

以上示例将输出

1
2
3

能够从生成器显式返回最终值是一个非常有用的功能。这是因为它允许生成器返回最终值(可能来自某种协程计算),客户端代码可以专门处理该最终值。这比强制客户端代码首先检查是否已产出最终值,然后如果已产出,再专门处理该值要简单得多。

生成器委托

生成器现在可以委托给另一个生成器、Traversable 对象或 数组,而无需使用 yield from 结构在最外层生成器中编写样板代码。

<?php
function gen()
{
yield
1;
yield
2;
yield from
gen2();
}

function
gen2()
{
yield
3;
yield
4;
}

foreach (
gen() as $val)
{
echo
$val, PHP_EOL;
}
?>

以上示例将输出

1
2
3
4

使用 intdiv() 进行整数除法

新的 intdiv() 函数执行其操作数的整数除法并返回结果。

<?php
var_dump
(intdiv(10, 3));
?>

以上示例将输出

int(3)

会话选项

session_start() 现在接受一个 数组 作为选项,这些选项会覆盖通常在 php.ini 中设置的 会话配置指令

这些选项也已扩展为支持 session.lazy_write(默认启用),它使 PHP 仅在会话数据更改时才覆盖任何会话文件;以及 read_and_close,这是一个只能传递给 session_start() 的选项,用于指示应读取会话数据,然后立即关闭未更改的会话。

例如,要将 session.cache_limiter 设置为 private 并读取后立即关闭会话

<?php
session_start
([
'cache_limiter' => 'private',
'read_and_close' => true,
]);
?>

preg_replace_callback_array()

新的 preg_replace_callback_array() 函数允许在使用 preg_replace_callback() 函数时编写更简洁的代码。在 PHP 7 之前,每个正则表达式都需要执行的回调需要回调函数包含大量分支逻辑。

现在,可以使用关联数组将回调注册到每个正则表达式,其中键是正则表达式,值是回调。

CSPRNG 函数

添加了两个新函数,以跨平台的方式生成密码安全的整数和字符串:random_bytes()random_int()

list() 始终可以解包实现 ArrayAccess 的对象

以前,list() 无法保证与实现 ArrayAccess 的对象一起正确操作。此问题现已修复。

其他特性

  • 添加了克隆时的类成员访问,例如 (clone $foo)->bar()
添加注释

用户贡献注释 2 条注释

60
Adrian Wiik
4 年前
记住宇宙飞船运算符表达式返回结果的一个好经验法则是将宇宙飞船运算符替换为减号 (-)。如果结果为负数、0 或正数,则表达式将分别返回 -1、0 或 1。

示例
<?php
echo 5 <=> 8; // 5 - 8 = -3,打印 -1
echo 2 <=> 2; // 2 - 2 = 0,打印 0
echo 4 <=> 2; // 4 - 2 = 2,打印 1
16
Julian Sawicki
4 年前
在 php 7.0 中,可以以类似于 JavaScript 的方式进行函数柯里化。

<?php

// 柯里化函数
function add($a) {
return function(
$b) use ($a) {
return
$a + $b;
};
}

// 在 PHP 7 中调用柯里化函数
$result = add(10)(15);

var_dump($result); // int 25

?>

在 php 5.6 中无法通过这种方式进行柯里化。
To Top