PHP 8.4:主要功能和改进

PHP 8.4 终于来了,它带来了令人兴奋的变化,将彻底改变开发人员的工作方式!随着每个新版本的发布,PHP 不断证明为什么它是当今 Web 开发领域中如此重要的工具。

先决条件

本文假设您具有 PHP 编程语言的基本知识。

我用于 PHP 开发的软件

  • Laravel Herd:用于管理我的 PHP 版本和 Nginx 服务器。
  • PHPStorm:一款具有良好 IntelliSense 和 AI 副驾驶的优秀 IDE。
  • Laragon:一个易于使用的本地开发环境,支持PHP和其他技术。
  • 不对称属性可见性(版本 2)🔓🔒

    在 PHP 中,对象属性的可见性传统上是对称的。这意味着属性的 `get` 和 `set` 操作必须具有相同的可见性(public、private 或 protected),但不能有差异。

    例如,如果一个属性是公共的,那么对它的读取和写入都是公共的,并且不可能只允许一个操作而不允许另一个操作。

    在上下文中,当您将类的属性声明为“public”时,它就变为可变的,从而允许从类外部读取和修改它。

    然而,随着不对称可见性的出现,您现在可以为读取和写入属性定义单独的范围。

    这意味着一个属性可以在一个上下文中可读,而在另一个上下文中可写,从而可以更好地控制如何访问和修改属性。

    class Animal{
      public private(set) string $name;
    
      public setName(string $foo){
        $ths->name = $foo;
      }
    }
    
    $animal = new Animal();
    
    echo $animal->name; // This will run correctly

    我们可以将属性设为“public”,将“set”属性设为“private”。这意味着该属性无法在类外更新,从而使其不可变。

    如果您尝试修改 `$name` 属性,您将收到一个错误,显示由于可见性范围,您无法修改该属性。

    Error trying to set private property (author’s image)

    以下是关于不对称可见性的几个需要注意的关键点:

  • set-visibility 声明中不允许有空格。 private(set) 是正确的。 private( set ) 不正确,将导致解析错误。
  • 如果将属性声明为公共,则可以省略主要可见性。例如,public private(set) 和 private(set) 的行为相同,因为隐含了公共可见性。
  • 只有类型化属性才允许对集合操作具有单独的可见性。这意味着您无法在 PHP 中对非类型化属性应用非对称可见性。
  • 设置可见性必须与获取可见性相同或更严格。例如,public protected(set) 和 protected protected(set) 均有效,但 protected public(set) 将导致语法错误。
  • 了解有关不对称可见性的更多信息,包括供您细阅的其他示例。

    属性钩子🪝

    属性钩子是 PHP 8.4 的一个重要特性,它为开发人员提供了一种将“get”和“set”指令直接添加到变量的方法,而无需明确创建读取和写入变量的方法。

    或者,可以使用`__get`和`__set`魔术方法,但这会使代码更加冗长,可能引入错误,并破坏静态分析工具。

    可以肯定地说,属性钩子的设计和语法与 Kotlin 类似,但主要受到“C#”和 Swift 编程语言的影响。

    在 PHP 8.3 中,我们可以在其构造函数中创建一个带有属性的“类”,它使我们能够读取和写入该属性。

    class Car {
        public function __construct(public string $model) { }
    }

    这种方法的问题在于,当我们决定写入属性时,我们要么使用“__set”魔术方法,要么明确地创建一个方法来改变变量,这可能会导致代码库中断。

    属性挂钩允许开发人员在创建属性后立即创建“set”指令。

    class Car{
      public string $model{
        set (string $value) {
          if(strlen($value) === 0){
            throw new ValueError("Model name cannot be empty");
          }
          $this->model = $value;
        }
      }
    }

    请注意,传递给 `set` 指令的值必须与属性是相同的类型,否则将引发错误。

    您可以将另一种类型传递给 `set` 指令,并在写入属性之前将其转换为正确的类型,如下所示:

    class Car{
      public string $year{
        set (string|number $value) {
          $year = intval($value);
          if($year < 2000){
            throw new ValueError("We only accept cars produced in year 2000 and above");
          }
          $this->year= $value;
        }
      }
    }

    上面的例子展示了我们如何安全地从 `set` 指令接收复合类型变量并将其解析为属性定义的正确类型。

    如果传递给 `set` 指令的参数与属性类型相同,则可以省略该参数。例如,下面的两种方法有效且行为类似。

    // --------------------------METHOD 1----------------------------
    public string $model{
        set (string $value) {
          if(strlen($value) === 0){
            throw new ValueError("Model name cannot be empty");
          }
          $this->model = $value;
        }
     }
    
    // --------------------------METHOD 2----------------------------
    public string $model{
        set {
          if(strlen($value) === 0){
            throw new ValueError("Model name cannot be empty");
          }
          $this->model = $value;
        }
      }

    请注意,如果省略参数,则默认为“$value”。此语法在 Kotlin 和“C#”等编程语言中很常见。

    实例化类时无需额外的括号

    在此功能之前,访问 PHP 中的类成员需要在类周围添加额外的括号。

    class Car {
    
      public function getName(){
        return "Toyota Camry";
      }
    }
    
    $carName = (new Car())->getName();

    如果您没有将“new Car()”调用括在括号中,则会收到解析错误。

    新的语法允许我们访问方法、属性和常量,而无需额外的括号。

    class Car {
      const TYPE = "vehicle";
    
      public function getName(){
        return "Toyota Camry";
      }
    }
    
    $carName = new Car()->getName();
    echo new Car()::TYPE;

    要全面了解此提议的变更,请查看 RFC 中的详细信息。

    引入新的数组函数

    PHP 8.4 即将推出新的辅助功能。

    其中一些功能已经在 Laravel `Arr` 或 `Collection` 助手中实现。

    **array_find_key() 函数**

    `array_find_key($array, $callback)` 函数返回 `$callback` 方法返回 true 的第一个元素的键。如果没有元素满足条件,则该函数返回 `null`。

    function array_find_key($array, $callback) {
        foreach ($array as $key => $value) {
            if ($callback($value)) {
                return $key;
            }
        }
        return null;
    }
    
    // Example array
    $numbers = [1, 2, 3, 4, 5];
    
    // Callback to find the key of the first element greater than 3
    $key = array_find_key($numbers, function($value) {
        return $value > 3;
    });
    
    echo $key;  // Output: 3 (the key of the value 4)

    **array_find() 函数**

    `array_find_key()` 函数用于搜索数组并返回满足回调函数定义的条件的第一个元素的键。

    与“array_find_key()”类似,如果未找到匹配元素,则返回 null。

    // Sample array
    $fruits = [
        'apple' => 5,
        'banana' => 12,
        'cherry' => 8,
        'date' => 15
    ];
    
    // Find the key of the first fruit with quantity greater than 10
    $key = array_find_key($fruits, function($value) {
        return $value > 10;
    });
    
    echo $key;  // Output: banana

    如果数组中没有水果的数量大于 10,则该函数将返回“null”。

    **array_any() 函数**

    `array_any()` 函数确定数组中至少有一个元素是否满足所提供的评估函数指定的特定标准。

    如果至少有一个元素满足条件,则该函数返回“true”;否则,返回“false”。

    // Sample array
    $numbers = [3, 8, 12, 5];
    
    // Check if there is any number greater than 10
    $result = array_any($numbers, function($value) {
        return $value > 10;
    });
    
    echo $result ? 'True' : 'False';  // Output: True

    如果数组中没有大于 10 的数字,则该函数将返回“false”。

    **array_all() 函数**

    `array_all()` 函数检查数组中的每个项目是否通过特定测试。它将特殊规则(回调函数)应用于每个项目。

    如果所有项目都根据规则通过测试,则“array_all()”返回“true”。

    在此示例中,`array_all()` 函数将遍历 `$numbers` 数组并将回调函数应用于每个元素。回调检查数字是否可以被 2 整除(即偶数)。

    由于数组中的所有数字都是偶数,因此 `array_all()` 函数将返回 `true`,并显示消息“所有数字都是偶数。”。

    我们研究了 PHP 8.4 中引入的关键改进。这些更新为开发人员提供了有价值的增强功能,包括强大的新功能和潜在的效率提升。

    要深入了解所有更新,包括示例和详细说明,请访问官方 PHP 8.4.0 发布公告页面。

    不要忘记检查弃用和向后兼容性变化,以确保顺利过渡到最新版本。

    下一步是什么?🫡

  • 如果您喜欢这篇文章,请不要忘记与他人分享。
  • 我很想听听你的想法——在下面发表评论,让我们继续对话。干杯!🎉
  • 关注我,了解更多 PHP、Node.js、TypeScript 和 PHP 文章!您也可以在 Twitter 或 LinkedIn 上找到我。