class Status
{
    const DRAFT = 'draft';
    const PUBLISHED = 'published';
    const ARCHIVED = 'archived';
}
function acceptStatus(string $status) {...}enum Status
{
    case Draft;
    case Published;
    case Archived;
}
function acceptStatus(Status $status) {...}class BlogData
{
    private Status $status;
   
    public function __construct(Status $status) 
    {
        $this->status = $status;
    }
    
    public function getStatus(): Status 
    {
        return $this->status;    
    }
}class BlogData
{
    public readonly Status $status;
   
    public function __construct(Status $status) 
    {
        $this->status = $status;
    }
}只读属性不能在初始化后更改,即在为它们分配值后。它们可以用于对值对象和数据传输对象建模。
$foo = [$this, 'foo'];
$fn = Closure::fromCallable('strlen');$foo = $this->foo(...);
$fn = strlen(...);现在可以获得对任何函数的引用。这统称为 First-class 可调用语法。
class Service 
{
    private Logger $logger;
 
    public function __construct(
        ?Logger $logger = null,
    ) {
        $this->logger = $logger ?? new NullLogger();
    }
}class Service 
{
    private Logger $logger;
    
    public function __construct(
        Logger $logger = new NullLogger(),
    ) {
        $this->logger = $logger;
    }
}对象现在可以用作默认参数值、静态变量和全局常量,以及属性参数。
这有效地使使用 嵌套属性 成为可能。
class User 
{
    /**
     * @Assert\All({
     *     @Assert\NotNull,
     *     @Assert\Length(min=5)
     * })
     */
    public string $name = '';
}class User 
{
    #[\Assert\All(
        new \Assert\NotNull,
        new \Assert\Length(min: 5))
    ]
    public string $name = '';
}function count_and_iterate(Iterator $value) {
    if (!($value instanceof Countable)) {
        throw new TypeError('value must be Countable');
    }
    foreach ($value as $val) {
        echo $val;
    }
    count($value);
}function count_and_iterate(Iterator&Countable $value) {
    foreach ($value as $val) {
        echo $val;
    }
    count($value);
}当一个值需要同时满足多个类型约束时,使用交集类型。
注意,目前无法将交集和联合类型混合在一起,例如 A&B|C。
function redirect(string $uri) {
    header('Location: ' . $uri);
    exit();
}
 
function redirectToLoginPage() {
    redirect('/login');
    echo 'Hello'; // <- dead code
}function redirect(string $uri): never {
    header('Location: ' . $uri);
    exit();
}
 
function redirectToLoginPage(): never {
    redirect('/login');
    echo 'Hello'; // <- dead code detected by static analysis 
}使用 never 类型声明的函数或方法表示它不会返回值,并且会抛出异常或通过调用 die()、exit()、trigger_error() 或类似的东西来结束脚本的执行。
class Foo
{
    public const XX = "foo";
}
class Bar extends Foo
{
    public const XX = "bar"; // No error
}class Foo
{
    final public const XX = "foo";
}
class Bar extends Foo
{
    public const XX = "bar"; // Fatal error
}可以声明 final 类常量,以禁止它们在子类中被重写。
016 === 16; // false because `016` is octal for `14` and it's confusing
016 === 14; // true 0o16 === 16; // false — not confusing with explicit notation
0o16 === 14; // true 现在可以使用显式 0o 前缀表示八进制数。
$httpClient->request('https://example.com/')
        ->then(function (Response $response) {
            return $response->getBody()->buffer();
        })
        ->then(function (string $responseBody) {
            print json_decode($responseBody)['code'];
        });$response = $httpClient->request('https://example.com/');
print json_decode($response->getBody()->buffer())['code'];Fibers 是用于实现轻量级协作并发的基础类型。它们是一种创建可以像生成器一样暂停和恢复的代码块的方法,但可以从堆栈中的任何位置进行。Fibers 本身并没有提供并发性,仍然需要一个事件循环。但是,它们允许通过阻塞和非阻塞实现共享相同的 API。
Fibers 允许摆脱以前在 Promise::then() 或基于生成器的协程中看到的样板代码。库通常会围绕 Fiber 构建进一步的抽象,因此无需直接与它们交互。
$arrayA = ['a' => 1];
$arrayB = ['b' => 2];
$result = array_merge(['a' => 0], $arrayA, $arrayB);
// ['a' => 1, 'b' => 2]$arrayA = ['a' => 1];
$arrayB = ['b' => 2];
$result = ['a' => 0, ...$arrayA, ...$arrayB];
// ['a' => 1, 'b' => 2]PHP 以前支持通过扩展运算符在数组内部解包,但前提是数组具有整数键。现在也可以使用字符串键解包数组。
#[ReturnTypeWillChange] 属性。fsync 和 fdatasync 函数。array_is_list 函数。Serializable 接口已弃用。$GLOBALS 变量限制。file_info 资源迁移到现有的 finfo 对象。IMAP\Connection 类对象。FTP\Connection 类对象。GdFont 类对象。LDAP\Connection、LDAP\Result 和 LDAP\ResultEntry 对象。PgSql\Connection、PgSql\Result 和 PgSql\Lob 对象。PSpell\Dictionary、PSpell\Config 类对象。