PHP Conference Japan 2024

新特性

PHP 核心

类型化属性

类属性现在支持类型声明。

<?php
class User {
public
int $id;
public
string $name;
}
?>
以上示例将强制执行 $user->id 只能分配 int 值,并且 $user->name 只能分配 string 值。

箭头函数

箭头函数 提供了一种简写语法,用于定义具有隐式按值作用域绑定的函数。

<?php
$factor
= 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);
// $nums = array(10, 20, 30, 40);
?>

有限的返回类型协变和参数类型逆变

以下代码现在可以工作了

<?php
class A {}
class
B extends A {}

class
Producer {
public function
method(): A {}
}
class
ChildProducer extends Producer {
public function
method(): B {}
}
?>
只有在使用自动加载时,才能获得完整的方差支持。在单个文件中,只允许非循环类型引用,因为所有类都需要在被引用之前可用。

空值合并赋值运算符

<?php
$array
['key'] ??= computeDefault();
// 大致等价于
if (!isset($array['key'])) {
$array['key'] = computeDefault();
}
?>

数组内部解包

<?php
$parts
= ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
// ['banana', 'orange', 'apple', 'pear', 'watermelon'];
?>

数字文字分隔符

数字文字可以在数字之间包含下划线。

<?php
6.674_083e-11
; // 浮点数
299_792_458; // 十进制
0xCAFE_F00D; // 十六进制
0b0101_1111; // 二进制
?>

弱引用

弱引用 允许程序员保留对对象的引用,而不会阻止该对象被销毁。

允许 __toString() 中抛出异常

现在允许从 __toString() 中抛出异常。以前这会导致致命错误。字符串转换中现有的可恢复致命错误已转换为 Error 异常。

CURL

CURLFile 现在除了支持普通文件名外,还支持流封装器,前提是扩展已针对 libcurl >= 7.56.0 构建。

Filter

FILTER_VALIDATE_FLOAT 过滤器现在支持 min_rangemax_range 选项,其语义与 FILTER_VALIDATE_INT 相同。

FFI

FFI 是一个新的扩展,它提供了一种简单的方法来调用本机函数、访问本机变量以及创建/访问 C 库中定义的数据结构。

GD

添加了 IMG_FILTER_SCATTER 图像过滤器,用于对图像应用散射过滤器。

Hash

使用 Castagnoli 多项式添加了 crc32c 哈希。此 CRC32 变体由存储系统(如 iSCSI、SCTP、Btrfs 和 ext4)使用。

多字节字符串

添加了 mb_str_split() 函数,它提供与 str_split() 相同的功能,但操作的是代码点而不是字节。

OPcache

已添加对 预加载代码 的支持。

正则表达式(Perl 兼容)

preg_replace_callback()preg_replace_callback_array() 函数现在接受一个额外的 flags 参数,并支持 PREG_OFFSET_CAPTUREPREG_UNMATCHED_AS_NULL 标志。这会影响传递给回调函数的匹配数组的格式。

PDO

现在可以在 mysql、mssql、sybase、dblib、firebird 和 oci 驱动程序的 PDO DSN 中指定用户名和密码。以前只有 pgsql 驱动程序支持此功能。如果在构造函数和 DSN 中都指定了用户名/密码,则构造函数优先。

现在可以在 SQL 查询中转义问号,以避免将其解释为参数占位符。编写 ?? 可以向数据库发送单个问号,例如使用 PostgreSQL JSON 键存在 (?) 运算符。

PDO_OCI

PDOStatement::getColumnMeta() 现在可用。

PDO_SQLite

PDOStatement::getAttribute(PDO::SQLITE_ATTR_READONLY_STATEMENT) 允许检查语句是否为只读,即它是否不会修改数据库。

PDO::setAttribute(PDO::SQLITE_ATTR_EXTENDED_RESULT_CODES, true) 启用在 PDO::errorInfo()PDOStatement::errorInfo() 中使用 SQLite3 扩展结果代码。

SQLite3

添加了 SQLite3::lastExtendedErrorCode() 用于获取最后一个扩展结果代码。

添加了 SQLite3::enableExtendedResultCodes($enable = true),这将使 SQLite3::lastErrorCode() 返回扩展结果代码。

标准

带标签名称数组的 strip_tags()

strip_tags() 现在也接受允许的标签数组:而不是 strip_tags($str, '<a><p>'),您现在可以编写 strip_tags($str, ['a', 'p'])

自定义对象序列化

添加了一种新的自定义对象序列化机制,它使用两种新的魔术方法:__serialize__unserialize

<?php
// 返回包含对象所有必要状态的数组。
public function __serialize(): array;

// 从给定的数据数组中恢复对象状态。
public function __unserialize(array $data): void;
?>
新的序列化机制取代了 Serializable 接口,该接口将在未来弃用。

没有参数的数组合并函数

array_merge()array_merge_recursive() 现在可以不带任何参数调用,在这种情况下,它们将返回一个空数组。这在结合使用扩展运算符时很有用,例如 array_merge(...$arrays)

proc_open() 函数

proc_open() 现在接受数组而不是字符串作为命令。在这种情况下,进程将直接打开(无需通过 shell),并且 PHP 将处理任何必要的参数转义。

<?php
proc_open
(['php', '-r', 'echo "Hello World\n";'], $descriptors, $pipes);
?>

proc_open() 现在支持 redirectnull 描述符。

<?php
// 类似于 shell 中的 2>&1
proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['redirect', 1]], $pipes);
// 类似于 shell 中的 2>/dev/null 或 2>nul
proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['null']], $pipes);
?>

没有 libargon 的 argon2i(d)

当 PHP 在没有 libargon 的情况下构建时,password_hash() 现在具有来自 sodium 扩展的 argon2i 和 argon2id 实现。

添加注释

用户贡献的注释 2 条注释

Rain
4 年前
需要注意的是,类型化属性在内部永远不会初始化为默认的 null。除非您自己将它们初始化为 null。这就是为什么如果您在初始化之前尝试访问它们,您总是会遇到此错误。

**类型化属性 foo::$bar 必须在初始化之前不可访问**

<?php
class User
{
public
$id;
public
string $name; // 类型化属性(未初始化)
public ?string $age = null; // 类型化属性(已初始化)
}

$user = new User;
var_dump(is_null($user->id)); // bool(true)
var_dump(is_null($user->name)); // PHP 致命错误:类型化属性 User::$name 必须在初始化之前不可访问
var_dump(is_null($user->age));// bool(true)
?>

另一件值得注意的事情是,无法将对象类型的属性初始化为除 null 之外的任何其他值。因为属性的评估发生在编译时,而对象实例化发生在运行时。最后一点,由于其上下文相关的行为,不可调用类型不受支持。
wow-apps.pro
4 年前
<?php

// 如何获取属性类型?例如用于测试:

class Foo
{
private
int $num;
private
bool $isPositive;
private
$notes;
}

$reflection = new \ReflectionClass(Foo::class);
$classProperties = $reflection->getProperties(\ReflectionProperty::IS_PRIVATE);
foreach (
$classProperties as $classProperty) {
var_dump((string) $classProperty->getType());
}

/**
* 结果:
* "int"
* "bool"
* ""
*/
To Top