PHP 8.5新特性体验
PHP 官方在11有20号正式发布了8.5版本,虽然没有异步的这种大特性。但是还是有不少新的值得体验的特性,下面我就说说这版的一些新特性。
Uri 扩展
这是一个新的uri类,是根据(RFC 3986)标准来实现的解析。相比以前使用parse_url函数,这个uri扩展就更符合面向对象方式了.
- 旧版本
$components = parse_url('https://php.net/releases/8.4/en.php');
var_dump($components['host']);
// string(7) "php.net"
- 新版本
use Uri\Rfc3986\Uri;
$uri = new Uri("https://example.com/path/to/resource?query=string#fragment");
var_dump($uri);
//class Uri\Rfc3986\Uri#1 (8) {
// public $scheme =>
// string(5) "https"
// public $username =>
// NULL
// public $password =>
// NULL
// public $host =>
// string(11) "example.com"
// public $port =>
// NULL
// public $path =>
// string(17) "/path/to/resource"
// public $query =>
// string(12) "query=string"
// public $fragment =>
// string(8) "fragment"
//}
管道操作符
这个应该是重量级的更新了,这个操作符其实和bash差不多。不过我感觉PHP这个管道符太难打了,也有点丑😂,还有就是感觉也不是特别的简便。来看看下面官方给得例子。
- 旧版本
$title = ' PHP 8.5 Released ';
$slug = strtolower(
str_replace('.', '',
str_replace(' ', '-',
trim($title)
)
)
);
var_dump($slug);
// string(15) "php-85-released"
- 新版本
$title = ' PHP 8.5 Released ';
$slug = $title
|> trim(...)
|> (fn($str) => str_replace(' ', '-', $str))
|> (fn($str) => str_replace('.', '', $str))
|> strtolower(...);
var_dump($slug);
// string(15) "php-85-released"
不知道你们发现没有,像str_replace这种多个参数的函数,它是需要一个匿名函数来包装下的。虽然老版本嵌套写起来不直观,这个写起也不是那么舒服😂。
克隆
现在可以通过向 clone() 函数传递关联数组,在对象克隆过程中更新属性。这使得对只读类的“with-er”模式能够得到直接支持。
- 旧版本
readonly class Color
{
public function __construct(
public int $red,
public int $green,
public int $blue,
public int $alpha = 255,
) {}
public function withAlpha(int $alpha): self
{
$values = get_object_vars($this);
$values['alpha'] = $alpha;
return new self(...$values);
}
}
$blue = new Color(79, 91, 147);
$transparentBlue = $blue->withAlpha(128);
- 新版本
readonly class Color
{
public function __construct(
public int $red,
public int $green,
public int $blue,
public int $alpha = 255,
) {}
public function withAlpha(int $alpha): self
{
return clone($this, [
'alpha' => $alpha,
]);
}
}
$blue = new Color(79, 91, 147);
$transparentBlue = $blue->withAlpha(128);
# 如果这个类不是只读类你还可以这样
$secBlus = clone($blue, [
'red' => 0,
'green' => 0,
'blue' => 255,
]);
var_dump($secBlus);
//class Color#3 (4) {
// public int $red =>
// int(0)
// public int $green =>
// int(0)
// public int $blue =>
// int(255)
// public int $alpha =>
// int(255)
//}
#[\NoDiscard] Attribute
添加过#[\NoDiscard]属性的函数, PHP会检查返回值是否已被使用,如果未被使用则发出警告。这有助于提高 API的安全性,尤其是在返回值至关重要但又容易被意外遗忘的情况下。我个人认为这个功能不是特别重要,在现在IDE的加持下这种函数IDE能识别出来,并会给出警告⚠️。
#[\NoDiscard]
function getPhpVersion(): string
{
return 'PHP 8.5';
}
getPhpVersion();
// 发出下面的警告
// Warning: The return value of function getPhpVersion() should
// either be used or intentionally ignored by casting it as (void)
常量表达式中的闭包和一等可调用对象
现在可以在常量表达式中使用静态闭包和一等可调用对象。这包括属性参数、属性和参数的默认值以及常量。
- 老版本
final class PostsController
{
#[AccessControl(
new Expression('request.user === post.getAuthor()'),
)]
public function update(
Request $request,
Post $post,
): Response {
// ...
}
}
- 新版本
<?php
final class PostsController
{
public function __construct(Closure $logger = static function (
string $message,
): void {echo $message, "\n";})
{
// ...
$logger("PostsController initialized.");
}
public final $callback = static function (): string {
// ...
return "Hello, World! \n";
};
#[AccessControl(static function (
Request $request,
Post $post,
): bool {
return $request->user === $post->getAuthor();
})]
public function update(
Request $request,
Post $post,
): Response {
// ...
}
}
echo (new PostsController()->callback)();
// PostsController initialized.
// Hello, World!
持久化的cURL句柄
使用curl_share_init_persistent()创建句柄,PHP 请求结束后,该句柄不会被销毁。如果找到具有相同共享选项集的持久共享句柄,则会重用该句柄,从而避免每次都初始化cURL句柄的开销。
- 旧版本
$sh = curl_share_init();
curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
$ch = curl_init('https://php.net/');
curl_setopt($ch, CURLOPT_SHARE, $sh);
curl_exec($ch);
- 新版本
$sh = curl_share_init_persistent([
CURL_LOCK_DATA_DNS,
CURL_LOCK_DATA_CONNECT,
]);
$ch = curl_init('https://php.net/');
curl_setopt($ch, CURLOPT_SHARE, $sh);
// 现在可能会重用先前SAPI的连接
curl_exec($ch);
array_first() and array_last() 函数
array_first() 和 array_last()函数分别返回数组的第一个值和最后一个值。如果数组为空,则返回 null(这样就很容易与??运算符组合使用)。说实话这两个函数在8.5才出来是真得太晚了。
<?php
$array = [
"a" => 1,
"b" => 2,
"c" => 3,
];
echo array_first($array), "\n"; // Outputs: 1
echo array_last($array), "\n"; // Outputs: 3