PHP 8 新特性

PHP 8 新特性 首页 / PHP7+入门教程 / PHP 8 新特性

PHP 8在这里!它于2020年11月26日发布。您可以在此处下载。这是新的主要版本,这意味着它将引入一些重大更改,以及许多新函数和性能改进。

由于重大更改,您很有可能需要对代码进行一些更改才能使其在PHP 8上运行。如果您始终与最新版本保持同步,则升级也不应该太很难,因为在7. *版本之前,大多数重大更改都已弃用。不用担心,所有这些弃用都列在这篇文章中。

除重大更改外,PHP 8还带来了一组不错的新函数,例如 JIT编译器联合类型属性等。

# Union types RFC

鉴于PHP的动态类型性质,在很多情况下联合类型可能有用。联合类型是两种或多种类型的集合,表示可以使用其中任何一种。

public function foo(Foo|Bar $input): int|float;

请注意, void 永远不能成为联合类型的一部分,因为它表示"没有返回值"。此外,可以使用|null或使用现有的?表示法:

public function foo(Foo|null $foo): void;

public function bar(?Bar $bar): void;

# JIT RFC

JIT(及时)编译器有望显着提高性能,尽管并不总是在Web请求的上下文中。已经在现实的Web应用程序上完成了自己的基准测试,似乎JIT并没有做到这一点如果有的话,在这些PHP项目上有很大的不同。

# The nullsafe operator RFC

如果您熟悉空合并运算符,那么您已经熟悉它的缺点:不会处理方法调用。相反,您需要进行中间检查,或依靠某些框架提供的 options 帮助器:

$startDate = $booking->getStartDate();
$dateAsString = $startDate ? $startDate->asDateTimeString() : null;

通过添加nullsafe运算符,现在可以在方法上具有类似于null合并的行为!

$dateAsString = $booking->getStartDate()?->asDateTimeString();

# 命名参数 RFC

命名参数允许您通过指定值名称将值传递给函数,这样您就不必按其顺序考虑在内,您还可以跳过可选参数!

function foo(string $a, string $b, ?string $c = null, ?string $d = null) 
{ /* … */ }

foo(
    b: 'value b', 
    a: 'value a', 
    d: 'value d',
);

# Attributes RFC

属性(在其他语言中通常称为注释)提供了一种向类添加元数据的方法,而无需解析文档块。

快速浏览一下,这是RFC中的属性样式示例:

use App\Attributes\ExampleAttribute;

#[ExampleAttribute]
class Foo
{
    #[ExampleAttribute]
    public const FOO = 'foo';
 
    #[ExampleAttribute]
    public $x;
 
    #[ExampleAttribute]
    public function foo(#[ExampleAttribute] $bar) { }
}
#[Attribute]
class ExampleAttribute
{
    public $value;
 
    public function __construct($value)
    {
        $this->value = $value;
    }
}

请注意,此基础Attribute过去被称为PhpAttribute在原始RFC中,但后来被另一个RFC 更改。

# Match表达式 RFC

您可以称其为 switch 表达式: match 可以返回值,不需要 break 语句,可以组合条件,使用严格的类型比较,不执行任何类型强制。

看起来像这样:

$result = match($input) {
    0 => "hello",
    '1', '2', '3' => "world",
};

# 增强构造函数 RFC

该RFC添加了语法糖来创建值对象或数据传输对象。现在,PHP可以将它们组合为一个,而不必为它们指定类属性和构造函数。

而不是这样做:

class Money 
{
    public Currency $currency;
 
    public int $amount;
 
    public function __construct(
        Currency $currency,
        int $amount,
    ) {
        $this->currency = $currency;
        $this->amount = $amount;
    }
}

您现在可以执行以下操作:

class Money 
{
    public function __construct(
        public Currency $currency,
        public int $amount,
    ) {}
}

# 新static返回类型 RFC 

虽然已经可以返回 self ,但 static 直到PHP 8才是有效的返回类型。考虑到PHP具有动态类型化的特性,它对许多开发人员都非常有用。

class Foo
{
    public function test(): static
    {
        return new static();
    }
}

# 新 mixed 类型 RFC

mixed类型会导致许多人产生混杂的感觉。不过,有一个很好的论据:缺少类型可能意味着在PHP中会有很多事情

请注意,mixed也可以用作参数或属性类型,而不仅仅是返回类型。

另请注意,由于mixed已包含null,不允许将其设为可空值。以下内容将触发错误:

// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.
function bar(): ?mixed {}

# Throw expression RFC

该RFC将 throw 从一个语句更改为一个表达式,这使得在许多新地方引发异常成为可能:

$triggerError = fn () => throw new MyError();

$foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset');

# Weak maps RFC

基于PHP 7.4中添加的弱引用RFC WeakMap 实现。 WeakMap 保存对对象的引用,不会阻止这些对象被垃圾回收。

以ORM为例,它们通常实现缓存,该缓存保存对实体类的引用,以提高实体之间关系的性能。只要该高速缓存具有对它们的引用,就不能对其进行垃圾回收,即使该高速缓存是引用它们的 only 事物也是如此。

如果此缓存层使用了弱引用和映射,则PHP将在没有其他引用的情况下对这些对象进行垃圾收集。尤其是在ORM的情况下,它可以管理一个请求中的数百个(如果不是数千个)实体。弱映射可以提供一种更好,更资源友好的方式来处理这些对象。

这是弱映射的样式,这是RFC中的一个示例:

class Foo 
{
    private WeakMap $cache;
 
    public function getSomethingWithCaching(object $obj): object
    {
        return $this->cache[$obj]
           ??= $this->computeSomethingExpensive($obj);
    }
}

# 在对象上允许 ::class RFC

一个小的但有用的新函数:现在可以在对象上使用 ::class ,而不必使用get_class()。其工作方式与 get_class()相同。

$foo = new Foo();

var_dump($foo::class);

# Non-capturing catches RFC

每当您想在PHP 8之前捕获异常时,无论是否使用该变量,都必须将其存储在变量中。使用非捕获的捕获,您可以忽略变量,所以代替这个:

try {
    // Something goes wrong
} catch (MySpecialException $exception) {
    Log::error("Something went wrong");
}

您现在可以执行以下操作:

try {
    // Something goes wrong
} catch (MySpecialException) {
    Log::error("Something went wrong");
}

请注意,必须始终指定类型,不允许您使用空的 catch 。如果要捕获所有异常和错误,可以使用 Throwable 作为捕获类型。

# 从接口创建DateTime对象

您已经可以通过 DateTimeImmutable 创建 DateTime 对象对象。DateTime::createFromInterface(DateTimeInterface $other);

DateTimeImmutable::createFromInterface(DateTimeInterface $other);

# 新的Stringable接口 RFC

Stringable 接口可用于提示任何实现__toString()。每当一个类实现__toString()时,它都会自动实现接口,无需手动实现。

class Foo
{
    public function __toString(): string
    {
        return 'foo';
    }
}

function bar(string|Stringable $stringable) { /* … */ }

bar(new Foo());
bar('abc');

# 新的str_contains() 函数 RFC

有人可能会说早就应该这样做了,但是无涯教程终于不必再依靠 strpos()来知道一个字符串是否包含另一个字符串了。

而不是这样做:

if (strpos('string with lots of words', 'words') !== false) { /* … */ }

您现在可以执行此操作

if (str_contains('string with lots of words', 'words')) { /* … */ }

# 新 str_starts_with() and str_ends_with() 函数 RFC

现在已在核心中添加了这两个函数。

str_starts_with('haystack', 'hay'); // true
str_ends_with('haystack', 'stack'); // true

# 新 fdiv()函数 RFC

新的 fdiv()函数的作用类似于 fmod() intdiv()函数,该函数允许除以0。得到的不是错误,而是错误 INF -INF NAN 

#新 get_resource_id() 函数 PR

资源是PHP中的特殊变量,是指外部资源。一个示例是MySQL连接,另一个示例是文件句柄。

这些资源中的每一个都分配有一个ID,尽管以前唯一知道该ID的方法是将资源转换为 int :

$resourceId = (int) $resource;

PHP 8添加了 get_resource_id ()函数,从而使此操作更加明显且类型安全:

$resourceId = get_resource_id($resource);

# 增强抽象方法 RFC

特性可以指定必须由使用它们的类实现的抽象方法。需要注意的是:在PHP 8之前,这些方法实现的语法尚未经过验证。以下是有效的:

trait Test {
    abstract public function test(int $input): int;
}

class UsesTrait
{
    use Test;

    public function test($input)
    {
        return $input;
    }
}

当使用特征并实现其抽象方法时,PHP 8将执行正确的方法语法验证。这意味着您需要编写以下代码:

class UsesTrait
{
    use Test;

    public function test(int $input): int
    {
        return $input;
    }
}

# 串联优先 RFC

尽管PHP 7.4中已弃用该更改,但现在已生效。如果您要编写这样的内容:

echo "sum: " . $a + $b;

PHP以前会这样解释它:

echo ("sum: " . $a) + $b;

PHP 8将使其如此解释:

echo "sum: " . ($a + $b);

# 更严格的类型检查 RFC

在PHP 8之前,可以在数组,资源或对象上应用算术或按位运算符。这不可能了,将抛出 TypeError :类型>

[] % [42];
$object + 4;

# Reflection changes

不推荐使用几种反射方法:

现在,您应该使用 ReflectionType 来获取有关参数类型的信息:

$reflectionParameter->getType()->allowsNull();

如果类型是单一类型,则 ReflectionParameter::getType()返回 ReflectionNamedType  的实例

 $reflectionParameter->getType()->getName();
$reflectionParameter->getType()->isBuiltin();

但是,如果该类型是联合类型,则将获得 ReflectionUnionType 的实例,该实例可以为您提供一个 ReflectionNamedType 像这样:

$reflectionParameter->getType()->getTypes();

可以使用 instanceof 检查来检查类型是否为联合:

if ($reflectionParameter->getType() instanceof ReflectionNamedType) { 
    // It's a single type
}

if ($reflectionParameter->getType() instanceof ReflectionUnionType) {
    // It's a union type
}

接下来,反射类的三个方法语法已更改:

ReflectionClass::newInstance($args);
ReflectionFunction::invoke($args);
ReflectionMethod::invoke($object, $args);

现在变成:

ReflectionClass::newInstance(...$args);
ReflectionFunction::invoke(...$args);
ReflectionMethod::invoke($object, ...$args);

升级指南指定,如果您扩展这些类,并且仍要同时支持PHP 7和PHP 8,则允许以下语法:

ReflectionClass::newInstance($arg = null, ...$args);
ReflectionFunction::invoke($arg = null, ...$args);
ReflectionMethod::invoke($object, $arg = null, ...$args);

祝学习愉快!(内容编辑有误?请选中要编辑内容 -> 右键 -> 修改 -> 提交!)

技术教程推荐

Linux实战技能100讲 -〔尹会生〕

Node.js开发实战 -〔杨浩〕

分布式技术原理与算法解析 -〔聂鹏程〕

Django快速开发实战 -〔吕召刚〕

代码之丑 -〔郑晔〕

手把手教你玩音乐 -〔邓柯〕

大数据经典论文解读 -〔徐文浩〕

郭东白的架构课 -〔郭东白〕

结构思考力 · 透过结构看表达 -〔李忠秋〕

好记忆不如烂笔头。留下您的足迹吧 :)