Code前端首页关于Code前端联系我们

PHP 7.4 有哪些新功能?为什么PHP8值得期待?

terry 2年前 (2023-09-25) 阅读数 52 #后端开发

事实上,尽管 PHP 7.4 显着提高了性能并提高了代码可读性,但既然 JIT 包含建议已获得批准,PHP 8 仍然将是 PHP 性能的真正里程碑。

无论如何,今天我们将介绍 PHP 7.4 中一些最有趣的功能和变化。在阅读本文之前,请务必保存以下日期:

6 月 6 日:PHP 7.4 Alpha 1
7 月 18 日:PHP 7.4 Beta 1 – 功能冻结
11 月 28 日:PHP 7.4 GA 发布

您可以请参阅 RFC 官方页面上的功能和附加组件的完整列表。

PHP 7.4 发布日期:
PHP 7.4 计划于 2019 年 11 月 28 日发布。这是 PHP 7 的下一个次要版本,应该会再次提高性能并使您的代码更具可读性/可维护性。

PHP 7.4 中有哪些新功能?

本文讨论了 PHP 7.4 最终版本中应添加到该语言中的一些更改和功能:

  • 支持数组内展开 - 展开运算符数组扩展
  • 箭头函数 2.0(较短的闭包)
  • NULL 连接运算符
  • 弱引用
  • 协变返回和逆变参数
  • 预加载
  • 新的自定义对象序列化机制

性能改进,数组表达式扩展运算符在…中引入Na自 PHP 5.6 起,参数解包 是将字符串和 Traversable 解包到参数列表中的语法。要解压数组或 Traversable,它必须以 ...(3 个点)作为前缀,如下例所示:
function test(...$args) { var_dump($args); }
test(1, 2, 3);

但是,PHP 7.4 RFC 建议将此功能扩展到数组来定义:

$arr = [...$args];

Spread 操作符的第一个优点是性能,RPC文档指出:

Spread操作符应该比array_merge有更好的性能。不仅扩展运算符是语法结构,array_merge 方法也是。即使在编译时,常量字段也会进行优化以实现高效率。

Spread 运算符的一个重要优点是它支持任何可遍历的对象,而 array_merge 函数仅支持数组。以下是使用 Spread 运算符的数组中的参数示例:

$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
var_dump($fruits);

如果在 PHP 7.3 或更早版本中运行此代码,PHP 将抛出解析错误:

Parse error: syntax error, unexpected '...' (T_ELLIPSIS), expecting ']' in /app/spread-operator.php on line 3

相反,PHP 7.4 将返回一个数组

array(5) {
    [0]=>
    string(6) "banana"
    [1]=>
    string(6) "orange"
    [2]=>
    string(5) "apple"
    [3]=>
    string(4) "pear"
    [4]=>
    string(10) "watermelon"
  }

RFC 规定同一个数组可以重复多次,我们来扩展一下。此外,我们可以在数组中的任何位置使用扩展运算符语法,因为我们可以在扩展运算符之前或之后添加公共元素。因此,以下代码将按预期工作:

$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$arr3 = [...$arr1, ...$arr2];
$arr4 = [...$arr1, ...$arr3, 7, 8, 9];

函数作为参数返回的数组也可以传递给新数组:

function buildArray(){
    return ['red', 'green', 'blue'];
}
$arr1 = [...buildArray(), 'pink', 'violet', 'yellow'];

PHP 7.4 输出以下数组:

array(6) {
    [0]=>
    string(3) "red"
    [1]=>
    string(5) "green"
    [2]=>
    string(4) "blue"
    [3]=>
    string(4) "pink"
    [4]=>
    string(6) "violet"
    [5]=>
    string(6) "yellow"
}

您还可以使用 发电机

function generator() {
    for ($i = 3; $i <= 5; $i++) {
        yield $i;
    }
  }
  $arr1 = [0, 1, 2, ...generator()];

,但召唤后不允许干预。考虑以下示例:

$arr1 = ['red', 'green', 'blue'];
$arr2 = [...&$arr1];

如果我们尝试通过引用传递,PHP 将发出以下解析错误:

Parse error: syntax error, unexpected '&' in /app/spread-operator.php on line 3

如果第一个数组的元素通过引用存储,则第二个数组的元素也通过引用存储数组中的引用。这是一个示例:

$arr0 = 'red';
  $arr1 = [&$arr0, 'green', 'blue'];
  $arr2 = ['white', ...$arr1, 'black'];

这就是 PHP 7.4 中的内容:

array(5) {
    [0]=>
    string(5) "white"
    [1]=>
    &string(3) "red"
    [2]=>
    string(5) "green"
    [3]=>
    string(4) "blue"
    [4]=>
    string(5) "black"
  }

箭头函数 2.0(短闭包)

在 PHP 中,匿名函数被认为非常冗长且难以实现和维护, RFC建议引入更简单、更清晰的箭头函数语法(或简短的结论),以便我们可以简洁地编写代码。 PHP 7.4之前:

function cube($n){
    return ($n * $n * $n);
  }
  $a = [1, 2, 3, 4, 5];
  $b = array_map('cube', $a);
  print_r($b);

PHP 7.4允许更简洁的语法,上面的函数可以重写如下:

$a = [1, 2, 3, 4, 5];
  $b = array_map(fn($n) => $n * $n * $n, $a);
  print_r($b);

目前,由于语言结构的原因,可以 匿名函数 (闭包) ) set use 继承父作用域中定义的变量,如下所示:

$factor = 10;
  $calc = function($num) use($factor){
    return $num * $factor;
  };

但在 PHP 7.4 中,父作用域的值是隐式捕获的(隐式绑定到值作用域)。所以我们一行就可以完成这个功能。

$factor = 10;
  $calc = fn($num) => $num * $factor;

在父作用域中定义的变量可用于箭头函数。相当于我们的useuse,父级无法更改。 。新语法是对语言的巨大改进,使我们能够构建更具可读性和可维护性的代码。

NULL串联运算符

由于日常使用中存在大量三元表达式和isset()一起使用的情况,我们添加了NULL串联运算符(??)这个语法糖。如果变量存在且不为 NULL,则返回其自己的值,否则返回其第二个操作数。

$username = $_GET['user'] ?? ‘nobody';

这段代码让事情变得非常简单:获取请求参数,如果不存在则设置默认值。但在这个 RFC 示例中,如果我们有更长的变量名怎么办?

$this->request->data['comments']['user_id'] = $this->request->data['comments']['user_id'] ?? 'value';

此代码很难长期维护。因此,为了帮助开发者写出更直观的代码,这个RFC建议引入null_coalesce_equal_operator ??=,这样我们就可以输入下面的代码替换上面的代码:

$this->request->data['comments']['user_id'] ??= ‘value’;

如果值为左边参数的值为 null,使用右边参数的值。

请注意,虽然串联运算符 ?? 是比较运算符,但 ??= 是赋值运算符。

类型属性 2.0

定义传递给函数或类的特定类型变量的类型声明、类型提示和方法。其中,类型提示是PHP5中提供的功能。在 PHP 7.2 中,添加了数据类型 object。 PHP7.4 增加了 主类属性声明 ,参见以下示例:

class User {
    public int $id;
    public string $name;
  }

除了 voidcallable 之外 支持所有类型 为什么不呢?你支持voidcallable吗?以下是 RFC 的解释

类型void不支持,因为它不可用且语义不清楚。
因为它没有用且语义不清楚。
类型 callable 不受支持,因为其行为依赖于上下文。

这样我们就可以放心使用了boolintfloat , 字符串, 物体可迭代self,当然还有很少使用的

“https://wiki.php.net/rfc /nullable_types">允许 nullable Null (?type)

所以在 PHP7.4 中你可以输入这样的代码:

// 静态属性的类型
  public static iterable $staticProp;

  // var 中声明属性
  var bool $flagl

  // 设置默认的值
  // 注意,只有 nullable 的类型,才能设置默认值为 null
  public string $str = "foo";
  public ?string $nullableStr = null;

  // 多个同类型变量的声明
  public float $x, $y;

如果我们传递一个不符合给定类型的变量会发生什么?

class User {
    public int $id;
    public string $name;
  }

  $user = new User;
  $user->id = 10;
  $user->name = [];

  // 这个会产生一个致命的错误
  Fatal error: Uncaught TypeError: Typed property User::$name must be string, array used in /app/types.php:9

弱引用

在此RFC中,建议引入类弱引用。弱引用允许编码保留对对象的引用,但这并不能防止对象被销毁。 ;这对于实现类似缓存的结构很有用。

提案作者示例Nikita Popov

$object = new stdClass;
  $weakRef = WeakReference::create($object);

  var_dump($weakRef->get());
  unset($object);
  var_dump($weakRef->get());

  // 第一次 var_dump
  object(stdClass)#1 (0) {}

  // 第二次 var_dump,当 object 被销毁的时候,并不会抛出致命错误
  NULL

协变回报和逆变参数

协方差和逆变
解释百度百科中的解释

  • 不变(Invariant):涵盖了所有需要的types
  • 协变:从通用到特定的类型
  • 逆变:从特定到通用的类型 目前 PHP 大多有 参数类型 Invariant ,而且大部分都是返回类型 Invariant 。这意味着当I是T的参数类型或返回类型时,子类也必须是T的参数类型或返回类型。 。但通常需要处理一些特殊情况,例如特殊返回类型或通用输入类型。提案RFC建议PHP7.4添加协变返回和逆变参数。以下是提案中的示例: 协变回报:
interface Factory {
  function make(): object;
}

class UserFactory implements Factory {
  // 将比较泛的 object 类型,具体到 User 类型
 function make(): User;
}

逆变参数:

interface Concatable {
  function concat(Iterator $input); 
}

class Collection implements Concatable {
  // 将比较具体的 `Iterator`参数类型,逆变成接受所有的 `iterable`类型
  function concat(iterable $input) {/* . . . */}
}

预加载

RFC由 Dmitry Stogov 提出。预加载是在模块初始化时将库和框架加载到OPCache中的过程,如下图PHP 7.4新增特性有哪些?为什么说PHP8值得期待?

引用他的原话:

在服务器启动时 - 在任何应用程序代码运行之前 - 我们可以加载一组特定的PHP文件存入内存,并使其内容“永久可用”以供该服务器处理的所有后续请求。这些文件中定义的所有函数和类都将立即可供请求使用,就像内部实体一样。
当服务器启动时 - 在我们运行任何应用程序代码之前 - 我们可以将一组 PHP 文件加载到内存中 - 并使其预加载内容对于所有后续请求“永久可用”。这些文件中定义的所有函数和类在请求时都可以立即使用,就像内置函数一样。

预加载由opcache.preload中的php.ini控制。该参数指定服务器启动时编译并执行的PHP脚本。该文件可用于预加载其他文件或通过函数 opcache_compile_file()

这是一个很大的性能改进,但也有 RFC

预加载文件保持缓存的明显缺点。如果不重新启动服务器,更改各自的源文件将不会产生任何影响。
预加载的文件将永久缓存在 opcache 中。修改相应的源文件时,除非重新启动服务,否则更改不会生效。

新的自定义对象序列化机制

这是Nikita Popov提出的另一项提案,并获得了绝大多数票数的批准。__sleep()和

$username = $_GET['user'] ?? ‘nobody';

__唤醒 () 魔法方法

  • 可串行化接口
  • 根据 Nikita 的说法,它们都有潜在的问题:导致代码复杂且不可靠。您可以在 RFC 中深入研究此主题。我只是在这里提到,新的序列化机制应该通过提供两个新的神奇方法 __serialize()__unserialize() 来防止这种情况发生,这两个方法结合了两个现有的问题机制。

    该提案以 20 票对 7 票通过。

    PHP7.4 中将弃用哪些功能?

    更改串联运算符优先级

    当前在 PHP 中,+- 算术运算符和 . 字符串运算符左连接,并且具有相同的一个优势。例如:

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

    在 PHP 7.3 中,此代码会生成以下警告:

    Warning: A non-numeric value encountered in /app/types.php on line 4

    这是因为此代码从左到右开始,所以它相当于:

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

    对于这个问题 这个 RFC 建议更改算子的优先级,使. 的优先级低于+- 这两个连接字符串之前始终使用运算符执行加法和减法。所以这行代码应该等价于如下:

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

    这个提案分为两步:

    • 从Php7.4开始运行,遇到+-。 如果不给予优先执行,将发出放弃通知。
    • PHP8 中将实现一个真正调整优先级的函数,以删除左关联三元运算符。在 PHP 中,三元运算符与许多其他语言的不同之处在于它是左结合的。根据 Nikita Popof 的说法: 对于在不同语言之间切换的程序员来说,这可能会令人困惑。例如,以下示例在 PHP 中是正确的: $b = $a == 1 ? ‘一’:$a==2? '二' : $a == 3? '三' : '其他';将被解释为:$b = (($a == 1 ? '一' : $a == 2) ? '二' : $a == 3 ) ? '三' : '其他';对于这种复杂的三重表示,它可能不会按照你想要的方式工作,而且很容易导致错误。因此这个RFC建议删除并放弃三元运算符的左结合使用,这要求程序员使用括号。此建议分两步实施:
    • 从 PHP7.4 开始,未显式使用括号的嵌套三元组将发出弃用警告。
    • 从 PHP 8.0 开始,编译时会出现错误。

    Php7.4 性能

    对 PHP 7.4 alpha 预览版的性能状态感到好奇,我今天对使用 Git Quick Benchmark 构建的 PHP 7.3.6、7.2.18、7.1.29 和 7.0.32 进行了一些测试每个发行版都是以相同的方式构建的。 PHP 7.4新增特性有哪些?为什么说PHP8值得期待?

    现阶段,PHPBench 7.4 的性能与稳定的 PHP 7.3 相当,已经比 PHP 7.0 快了约 30%……当然,与过去的 PHP 5.5 相比,收益甚至更大。 PHP 7.4新增特性有哪些?为什么说PHP8值得期待?

    以微米为单位,PHP 7.4 的运行速度仅比 PH​​P 7.3 稍快,而 PHP-8.0 的运行速度大致相同,至少在 JIT 代码稳定并默认启用之前是这样。 PHP 7.4新增特性有哪些?为什么说PHP8值得期待?

    在 Phoronix 自己的内部 PHP 基准测试中,PHP 7.4 似乎高于 PHP 7.3 的性能水平 - 至少在这个 pre-alpha 状态下是这样。自 PHP 7.0 以来已经有了一些重大改进,自 PHP5 缓慢发布以来也有许多改进。

    总结:PHP7.4是预期的版本,但PHP8是整个PHP世界中最重要的。

    版权声明

    本文仅代表作者观点,不代表Code前端网立场。
    本文系作者Code前端网发表,如需转载,请注明页面地址。

    发表评论:

    ◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

    热门