PHP 8.4.2 Released!

新特性

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
; // float
299_792_458; // decimal
0xCAFE_F00D; // hexadecimal
0b0101_1111; // binary
?>

弱引用

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

允许从 __toString() 抛出异常

现在允许从 __toString() 抛出异常。之前的版本,将会导致致命错误。新版本中,之前发生致命错误的代码,已经被转换为 Error 异常。

CURL

如果扩展是使用 libcurl >= 7.56.0 构建的,CURLFile 现在除了支持普通文件名之外还支持流封装协议。

Filter

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

FFI

FFI 是新扩展,提供了简单的方式去 C 库中调用原生函数、访问原生变量和创建和访问定义的数据结构。

GD

添加 IMG_FILTER_SCATTER 图片过滤器以将分散过滤器(scatter filter)应用于图片。

Hash

使用循环卷积多项式新增 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 flag。这会影响传递给回调函数的匹配数组的格式。

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() 用于获取最后的扩展结果代码(extended result code)。

新增 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)

在不使用 libargon 的情况下编译 PHP 时,password_hash() 现在由 sodium 扩展实现了 argon2i 和 argon2id 。

添加备注

用户贡献的备注 2 notes

up
94
Rain
4 years ago
It should be noted that typed properties internally are never initialized to a default null. Unless of course you initialize them to null yourself. That's why you will always going to encounter this error if you try to access them before initialization.

**Typed property foo::$bar must not be accessed before initialization**

<?php
class User
{
public
$id;
public
string $name; // Typed property (Uninitialized)
public ?string $age = null; // Typed property (Initialized)
}

$user = new User;
var_dump(is_null($user->id)); // bool(true)
var_dump(is_null($user->name)); // PHP Fatal error: Typed property User::$name must not be accessed before initialization
var_dump(is_null($user->age));// bool(true)
?>

Another thing worth noting is that it's not possible to initialize a property of type object to anything other than null. Since the evaluation of properties happens at compile-time and object instantiation happens at runtime. One last thing, callable type is not supported due to its context-dependent behavior.
up
10
wow-apps.pro
4 years ago
<?php

// How to get property type? For example for testing:

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());
}

/**
* Result:
* "int"
* "bool"
* ""
*/
To Top