PHP 大会日本 2024
已发布!
PHP 8.4 是 PHP 语言的一个主要更新。
它包含许多新特性,例如属性钩子、非对称可见性、更新的 DOM API、性能改进、错误修复和常规清理。

属性钩子 RFC 文档

PHP < 8.4
class Locale
{
private
string $languageCode;
private
string $countryCode;

public function
__construct(string $languageCode, string $countryCode)
{
$this->setLanguageCode($languageCode);
$this->setCountryCode($countryCode);
}

public function
getLanguageCode(): string
{
return
$this->languageCode;
}

public function
setLanguageCode(string $languageCode): void
{
$this->languageCode = $languageCode;
}

public function
getCountryCode(): string
{
return
$this->countryCode;
}

public function
setCountryCode(string $countryCode): void
{
$this->countryCode = strtoupper($countryCode);
}

public function
setCombinedCode(string $combinedCode): void
{
[
$languageCode, $countryCode] = explode('_', $combinedCode, 2);

$this->setLanguageCode($languageCode);
$this->setCountryCode($countryCode);
}

public function
getCombinedCode(): string
{
return
\sprintf("%s_%s", $this->languageCode, $this->countryCode);
}
}

$brazilianPortuguese = new Locale('pt', 'br');
var_dump($brazilianPortuguese->getCountryCode()); // BR
var_dump($brazilianPortuguese->getCombinedCode()); // pt_BR
PHP 8.4
class Locale
{
public
string $languageCode;

public
string $countryCode
{
set (string $countryCode) {
$this->countryCode = strtoupper($countryCode);
}
}

public
string $combinedCode
{
get => \sprintf("%s_%s", $this->languageCode, $this->countryCode);
set (string $value) {
[
$this->languageCode, $this->countryCode] = explode('_', $value, 2);
}
}

public function
__construct(string $languageCode, string $countryCode)
{
$this->languageCode = $languageCode;
$this->countryCode = $countryCode;
}
}

$brazilianPortuguese = new Locale('pt', 'br');
var_dump($brazilianPortuguese->countryCode); // BR
var_dump($brazilianPortuguese->combinedCode); // pt_BR
属性钩子提供对计算属性的支持,这些属性可以被 IDE 和静态分析工具原生理解,而无需编写可能不同步的文档块注释。此外,它们允许对值进行可靠的预处理或后处理,而无需检查类中是否存在匹配的 getter 或 setter。

非对称可见性 RFC 文档

PHP < 8.4
class PhpVersion
{
private
string $version = '8.3';

public function
getVersion(): string
{
return
$this->version;
}

public function
increment(): void
{
[
$major, $minor] = explode('.', $this->version);
$minor++;
$this->version = "{$major}.{$minor}";
}
}
PHP 8.4
class PhpVersion
{
public private(
set) string $version = '8.4';

public function
increment(): void
{
[
$major, $minor] = explode('.', $this->version);
$minor++;
$this->version = "{$major}.{$minor}";
}
}
现在可以独立于读取属性的范围来控制写入属性的范围,从而减少了需要样板 getter 方法来公开属性的值而无需允许从类外部修改的需求。

#[\Deprecated] 属性 RFC 文档

PHP < 8.4
class PhpVersion
{
/**
* @deprecated 8.3 请使用 PhpVersion::getVersion() 代替
*/
public function getPhpVersion(): string
{
return
$this->getVersion();
}

public function
getVersion(): string
{
return
'8.3';
}
}

$phpVersion = new PhpVersion();
// 没有提示方法已弃用。
echo $phpVersion->getPhpVersion();
PHP 8.4
class PhpVersion
{
#[
\Deprecated(
message: "use PhpVersion::getVersion() instead",
since: "8.4",
)]
public function
getPhpVersion(): string
{
return
$this->getVersion();
}

public function
getVersion(): string
{
return
'8.4';
}
}

$phpVersion = new PhpVersion();
// Deprecated: Method PhpVersion::getPhpVersion() is deprecated since 8.4, use PhpVersion::getVersion() instead
echo $phpVersion->getPhpVersion();
新的 #[\Deprecated] 属性使 PHP 现有的弃用机制可用于用户定义的函数、方法和类常量。

新的 ext-dom 特性和 HTML5 支持 RFC RFC 文档

PHP < 8.4
$dom = new DOMDocument();
$dom->loadHTML(
<<<'HTML'
<main>
<article>PHP 8.4 是一个功能丰富的版本!</article>
<article class="featured">PHP 8.4 添加了新的符合规范的 DOM 类,并保留旧类以保持兼容性。</article>
</main>
HTML,
LIBXML_NOERROR,
);

$xpath = new DOMXPath($dom);
$node = $xpath->query(".//main/article[not(following-sibling::*)]")[0];
$classes = explode(" ", $node->className); // 简化
var_dump(in_array("featured", $classes)); // bool(true)
PHP 8.4
$dom = Dom\HTMLDocument::createFromString(
<<<'HTML'
<main>
<article>PHP 8.4 is a feature-rich release!</article>
<article class="featured">PHP 8.4 adds new DOM classes that are spec-compliant, keeping the old ones for compatibility.</article>
</main>
HTML,
LIBXML_NOERROR,
);

$node = $dom->querySelector('main > article:last-child');
var_dump($node->classList->contains("featured")); // bool(true)

新的 DOM API 包括对解析 HTML5 文档的标准兼容支持,修复了 DOM 功能行为中一些长期存在的兼容性错误,并添加了一些函数以方便文档操作。

新的 DOM API 可在 Dom 命名空间中使用。使用新 DOM API 的文档可以使用 Dom\HTMLDocumentDom\XMLDocument 类创建。

BCMath 的对象 API RFC

PHP < 8.4
$num1 = '0.12345';
$num2 = 2;
$result = bcadd($num1, $num2, 5);

echo
$result; // '2.12345'
var_dump(bccomp($num1, $num2) > 0); // false
PHP 8.4
use BcMath\Number;

$num1 = new Number('0.12345');
$num2 = new Number('2');
$result = $num1 + $num2;

echo
$result; // '2.12345'
var_dump($num1 > $num2); // false

新的 BcMath\Number 对象允许在处理任意精度数字时使用面向对象的方法和标准数学运算符。

这些对象是不可变的,并实现了 Stringable 接口,因此它们可以在字符串上下文中使用,例如 echo $num

新的 array_*() 函数 RFC

PHP < 8.4
$animal = null;
foreach ([
'dog', 'cat', 'cow', 'duck', 'goose'] as $value) {
if (
str_starts_with($value, 'c')) {
$animal = $value;
break;
}
}

var_dump($animal); // string(3) "cat"
PHP 8.4
$animal = array_find(
[
'dog', 'cat', 'cow', 'duck', 'goose'],
static fn (
string $value): bool => str_starts_with($value, 'c'),
);

var_dump($animal); // string(3) "cat"
新的函数 array_find()array_find_key()array_any()array_all() 可用。

PDO 驱动程序特定的子类 RFC

PHP < 8.4
$connection = new PDO(
'sqlite:foo.db',
$username,
$password,
);
// object(PDO)

$connection->sqliteCreateFunction(
'prepend_php',
static fn (
$string) => "PHP {$string}",
);

$connection->query('SELECT prepend_php(version) FROM php');
PHP 8.4
$connection = PDO::connect(
'sqlite:foo.db',
$username,
$password,
);
// object(Pdo\Sqlite)

$connection->createFunction(
'prepend_php',
static fn (
$string) => "PHP {$string}",
);
// 在不匹配的驱动程序上不存在。

$connection->query('SELECT prepend_php(version) FROM php');
新的 PDO 子类 Pdo\DblibPdo\FirebirdPdo\MySqlPdo\OdbcPdo\PgsqlPdo\Sqlite 可用。

new MyClass()->method() 不带括号 RFC 文档

PHP < 8.4
class PhpVersion
{
public function
getVersion(): string
{
return
'PHP 8.3';
}
}

var_dump((new PhpVersion())->getVersion());
PHP 8.4
class PhpVersion
{
public function
getVersion(): string
{
return
'PHP 8.4';
}
}

var_dump(new PhpVersion()->getVersion());
现在可以访问新实例化对象的属性和方法,而无需将 new 表达式括在括号中。

新增类、接口和函数

  • 新增惰性对象
  • 基于 IR 框架的新 JIT 实现。
  • 新增 request_parse_body() 函数。
  • 新增 bcceil()bcdivmod()bcfloor()bcround() 函数。
  • round() 新增 RoundingMode 枚举,并包含 4 种新的舍入模式:TowardsZeroAwayFromZeroNegativeInfinityPositiveInfinity
  • 新增 DateTime::createFromTimestamp()DateTime::getMicrosecond()DateTime::setMicrosecond()DateTimeImmutable::createFromTimestamp()DateTimeImmutable::getMicrosecond()DateTimeImmutable::setMicrosecond() 方法。
  • 新增 mb_trim()mb_ltrim()mb_rtrim()mb_ucfirst()mb_lcfirst() 函数。
  • 新增 pcntl_getcpu()pcntl_getcpuaffinity()pcntl_getqos_class()pcntl_setns()pcntl_waitid() 函数。
  • 新增 ReflectionClassConstant::isDeprecated()ReflectionGenerator::isClosed()ReflectionProperty::isDynamic() 方法。
  • 新增 http_get_last_response_headers()http_clear_last_response_headers()fpow() 函数。
  • 新增 XMLReader::fromStream()XMLReader::fromUri()XMLReader::fromString()XMLWriter::toStream()XMLWriter::toUri()XMLWriter::toMemory() 方法。
  • 新增 grapheme_str_split() 函数。

弃用和向后兼容性中断

  • IMAP、OCI8、PDO_OCI 和 pspell 扩展已取消捆绑并迁移到 PECL。
  • 隐式可空参数类型现已弃用。
  • 使用 _ 作为类名现已弃用。
  • 将零提升到负数次幂现已弃用。
  • round() 传递无效模式现将抛出 ValueError
  • 来自 dateintlpdoreflectionsplsqlitexmlreader 扩展的类常量现在已进行类型化。
  • GMP 类现在是最终类。
  • 已移除 MYSQLI_SET_CHARSET_DIRMYSQLI_STMT_ATTR_PREFETCH_ROWSMYSQLI_CURSOR_TYPE_FOR_UPDATEMYSQLI_CURSOR_TYPE_SCROLLABLEMYSQLI_TYPE_INTERVAL 常量。
  • 已弃用 mysqli_ping()mysqli_kill()mysqli_refresh() 函数、mysqli::ping()mysqli::kill()mysqli::refresh() 方法和 MYSQLI_REFRESH_* 常量。
  • stream_bucket_make_writeable()stream_bucket_new() 现在返回 StreamBucket 实例,而不是 stdClass
  • exit() 行为更改.
  • 已弃用 E_STRICT 常量。
To Top