PHP 8.5 今天发布,以下是新内容。
PHP 8.5 gets released today, here's what's new

原始链接: https://stitcher.io/blog/new-in-php-85

## PHP 8.5 发布:主要更新 PHP 8.5 于 2025 年 11 月 20 日发布,为该语言带来了多项增强。一个突出的特性是 **管道操作符 (`|>`)**,它简化了函数链,使代码更易读。克隆对象现在支持在过程中直接分配新值,但 readonly 属性存在限制。 新的 **`#[NoDiscard]` 属性** 强制使用函数返回值,如果忽略则会触发警告(可以使用 `(void)` 强制转换来抑制)。**闭包现在可以在常量表达式中使用**,从而能够在属性中定义它们——这为动态配置提供了一个强大的补充。 其他改进包括 **致命错误的堆栈跟踪**,以便于调试,以及内置的 **`array_first()` 和 `array_last()` 函数**,用于更简单的数组操作。一个新的 **URI 解析器** 提供了增强的 URI 处理能力。通过 **`#[DelayedTargetValidation]`** 属性,可以改进属性的编译时验证,以实现向后兼容。 PHP 8.5 还包括各种较小的更改、弃用和破坏性更改——完整的列表可在 [此处](未在文本中提供完整列表的链接) 找到。

黑客新闻 新 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 PHP 8.5 今天发布,以下是新内容 (stitcher.io) 16 分,作者 brentroose,57 分钟前 | 隐藏 | 过去 | 收藏 | 讨论 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请YC | 联系 搜索:
相关文章

原文

Written on 2025-11-20

PHP 8.5 was released on November 20, 2025. It includes the pipe operator, clone with, a new URI parser, and more.


PHP 8.5 introduces the new pipe operator that makes chaining output from one function to another a lot easier. Instead of deeply nested function calls like this:

$input = ' Some kind of string. ';

$output = strtolower(
    str_replace(['.', '/', '…'], '',
        str_replace(' ', '-',
            trim($input)
        )
    )
);

You can now write this:

$output = $input
    |> trim(...)
    |> (fn (string $string) => str_replace(' ', '-', $string))
    |> (fn (string $string) => str_replace(['.', '/', '…'], '', $string))
    |> strtolower(...);

I've done a deep-dive into this new operator, and you can read about it here.


There's now a way to assign new values to cloned objects while cloning them:

final class Book
{
    public function __construct(
        public string $title,
        public string $description,
    ) {}

    public function withTitle(string $title): self
    {
        return clone($this, [
            'title' => $title,
        ]);
    }
}

I think this is a great feature. The only thing I find unfortunate is that it doesn't work when cloning readonly properties from the outside (which I think is a common use case). To do so, you have to specifically reset the propery's write access to public(set). I explained the problem here.


You can now mark a function with the #[NoDiscard] attribute, indicating that its return value must be used. If nothing happens with that return value, a warning will be triggered.

#[NoDiscard("you must use this return value, it's very important.")]
function foo(): string {
    return 'hi';
}




foo();


$string = foo();

The warning can still be surpressed by using the new (void) cast:

(void) foo();

Closures and first-class callables can now be used in constant expressions. In practice this means you'll be able to define closures in attributes, which is an incredible new feature:

#[SkipDiscovery(static function (Container $container): bool {
    return ! $container->get(Application::class) instanceof ConsoleApplication;
})]
final class BlogPostEventHandlers
{  }

Note that these kinds of closures must always be explicitly marked as static, since they aren't attached to a $this scope. They also cannot access variables from the outside scope with use.


A small but awesome change: fatal errors will now include backtraces.

Fatal error: Maximum execution time of 1 second exceeded in example.php on line 6
Stack trace:
#0 example.php(6): usleep(100000)
#1 example.php(7): recurse()
#2 example.php(7): recurse()
#3 example.php(7): recurse()
#4 example.php(7): recurse()
#5 example.php(7): recurse()
#6 example.php(7): recurse()
#7 example.php(7): recurse()
#8 example.php(7): recurse()
#9 example.php(7): recurse()
#10 example.php(10): recurse()
#11 {main}

Perhaps a bit overdue (array_key_first() and array_key_last() were added in PHP 7.3), but we finally get built-in functions to get the first and last elements from arrays! So instead of writing this:

$first = $array[array_key_first($array)] ?? null;

You can now write this:

$first = array_first($array);

There's a brand new URI implemention that makes working with URIs a lot easier:

use Uri\Rfc3986\Uri;

$uri = new Uri('https://tempestphp.com/2.x/getting-started/introduction');

$uri->getHost();
$uri->getScheme();
$uri->getPort();



Some built-in attributes (like #[Override]) are validated at compile-time rather than at runtime when being called via reflection. The #[DelayedTargetValidation] allows you to postpone that validation to a runtime:

class Child extends Base
{
	#[DelayedTargetValidation]
	#[Override]
	public const NAME = 'Child';

	
}

This attribute is added to manage backwards compatibility issues. You can read a concrete example here.


Smaller changes


Deprecations and breaking changes


Those are the features and changes that stand out for PHP 8.5; you can find the whole list of everything that's changed over here.

What are your thoughts about PHP 8.5? You can leave them in the comments below!

联系我们 contact @ memedata.com