PHP8来了!能战乎?

PHP8终于来了!

PHP8.0是PHP的一个重大更新。 它包含许多新的特点和优化其中包括 命名参数, 联合类型, 特性, 构造函数属性提升, match表达式, Null安全操作符, JIT,并改进了类型系统, 错误处理和 一致性问题。

在本文中,我们将审查所有新的特点和变化,并分享关于每一个变化的一些想法,而且从路线图上看来PHP似乎一直在向前发展。

你可以读取所有有关这些在官方发布的正式公告

新的功能

1. 命名参数

在PHP8调用一个函数时,可以省略非必需的参数,传递需要的。

命名参数的例子

function my_awesome_function(string $name, string $value = "", int $expires = 0) {
    ...
}

现在举个例子,我们要调用这一函数,但只有指定的 $name 和 $expires 属性。

在PHP7:

// calling the function. but we only want to specify $name and $expires
my_awesome_function('test', '', time() + 60 * 60 * 2)

在PHP8:

// calling the function. but we only want to specify $name and $expires
my_awesome_function(name: 'test', expires: time() + 60 * 60 * 2)

关于命名参数的想法

这是一个很好和方便改进。许多语言现在支持这种方法的函数调用。
然而,这一设计可能会因为给函数设置太多参数,导致函数功能复杂化,从而违反了单一职责原则(Single-responsibility principle)。因此,一如既往,谨慎使用;-)

2. 属性

属性是新来的小子。 它本质上是一种直接嵌入进入代码的配置语言。
属性是一个原生的PHP语法,在代码中为 类、方法、函数、参数、类属性等的声明,添加结构化和机器可读的元数据信息。

属性的例子

在PHP7(PHPDocs):

class BookController
{
    /**
     * @Route("/api/books/{id}", methods={"GET"})
     */
    public function get($id) { /* ... */ }
}

在PHP8:

class BookController
{
    #[Route("/api/books/{id}", methods: ["GET"])]
    public function get($id) { /* ... */ }
}

3. 构造函数属性提升

基本的想法很简单:把所有类属性和变量的定义赋值,和访问修饰符public, protected或 private直接放在构造函数的参数列表中。PHP处理这一新的语法,是在执行前先将其转化为一般语法的形式。

构造函数属性的例子

在PHP7:

class Point {
  public float $x;
  public float $y;
  public float $z;

  public function __construct(
    float $x = 0.0,
    float $y = 0.0,
    float $z = 0.0
  ) {
    $this->x = $x;
    $this->y = $y;
    $this->z = $z;
  }
}

在PHP8:

class Point {
  public function __construct(
    public float $x = 0.0,
    public float $y = 0.0,
    public float $z = 0.0,
  ) {}
}

关于构造函数属性提升的想法

构造函数属性提升减少了需要的代码量,让类更简洁。
如果你不想让类属性出现在构造函数参数列表中,可以用旧的方式声明它们,然后在构造函数内部初始化(或者不处理)。

4. 联合类型

联合类型是一种为属性和变类声明多个类型的方法。因此,如果一个函数的参数可以接受stringint类型的值,现在可以用 string|int来声明它.
在PHP7,你无法这样做,只有使用PHPDocs(这不是PHP核心库,只存在PHPDocs中).
你能用联合类型代替PHPDocs标记来声明多类型的变量,并且类型在运行时中会进行验证。

联合类型的例子

在PHP7:

class Book {
  /** @var int|float */
  private $price;

  /**
   * @param float|int $price
   */
  public function __construct($price) {
    $this->price = $price;
  }
}

new Book('test'); // OK at runtime

在PHP8,因为联合类型是PHP运行时和编译器的一部分,以下代码将会抛出错误:

class Book {
  public function __construct(
    private int|float $price
  ) {}
}

new Book('test'); // TypeError

关于联合类型的想法

作为一个SOLID原则的倡导者,我不是特别喜欢这个变化。
我可以理解的,它可以帮助加快速度,并提升了对代码的控制,但是我相信如果你的代码常常需要你用联合类型定义一个属性,那么肯定是有些东西更需要你去思考。

5. Match表达式

在PHP8中,match表达式语法是最好的特性之一,它从多方面改善switch语法。

让我们来比较一下这两种语法。 这是个经典 switch 的例子:

在PHP7(使用 switch):

switch ($statusCode) {
    case 200:
    case 300:
        $message = null;
        break;
    case 400:
        $message = 'not found';
        break;
    case 500:
        $message = 'server error';
        break;
    default:
        $message = 'unknown status code';
        break;
}

在PHP8(使用 match):

$message = match ($statusCode) {
    200, 300 => null,
    400 => 'not found',
    500 => 'server error',
    default => 'unknown status code',
};

关于Match表达式特性的思考

match 会做严格类型的检查,而不是宽松的。这就像的使用===,而不是==。在我看来,这是一个很好的机会,因为它使代码更严格和更富有表现力。
此外,如果你忘记检查参数值,并且没有指定默认匹配,PHP会抛出一个 UnhandledMatchError 异常。
再次更加严格,但是它将阻止细微的错误不会被忽视。
为了解决这个问题,你应该把 match表达式放在一个单独的方法内,捕捉并处理 UnhandledMatchError 异常,然后返回一个默认值。

6. Null安全操作符

过去用条件判断检测null值,现在能用null安全操作符进行链式调用。
当评价链中的一个要素失败,则执行的整个链条中止,整个链的计算结果为null。

Null安全操作符使用例子

在PHP7:

$country =  null;

if ($book !== null) {
  $author = $book->author;

  if ($author !== null) {
    $address = $author->getAddress();

    if ($address !== null) {
      $country = $address->country;
    }
  }
}

在PHP8:

$country = $book?->author?->getAddress()?->country;

关于null安全操作符的想法

我对这个新特性的感觉是复杂的。
当然,这是一个方便的功能,因为它导致更小的和更可读的编码。
但是,通过更高视角来看,为什么我们甚至需要检查如此之深,并贪婪地?
难道我们的代码不应该有业务规则来抑制这种行为吗? 因此,又是一个方便的新的特征,但谨慎使用…

合理的字符串和数字比较

当用一个数字与一个只含有数字的字符串进行比较时,PHP8采用数字比较。否则,它先将数字转化为字符串,然后在进行字符串比较。

在PHP7:

0 == 'foobar' // true

在PHP8:

0 == 'foobar' // false

这绝对是一个正确的发展方向,但也表明了PHP正试图成为一个更严格的语言。
当我们说相等时,应该意味着真正的相等!

关于PHP8的总体想法

PHP无疑正试图成为一个更加严格,甚至是更加”严肃”的一种语言。
作为一个OOP和SOLID原则的热衷者,我完全乐意和追随这个方向。
此外,正如你将在升级指导中看到的,PHP8通常是向后兼容的,因为它不会破坏很多之前主要版本的功能模块。 酷!

因此,让我们尽可能有意识的尝试用所有PHP的新特性去构建很棒的东西!

如果新版本的PHP能够满足你的需求,可以先看看迁移指南.
你对PHP8有什么想法?

0 0 vote
Article Rating
Subscribe
提醒
guest
0 评论
Inline Feedbacks
View all comments