PHP 7.4 新特新速看,预加载了解一下~

2024-04-25 14:58

本文主要是介绍PHP 7.4 新特新速看,预加载了解一下~,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

PHP 7.4 ,下一个 PHP 7 较小的发布版,期望在 2019 年 11 月 28 日发布。因此,现在是时候让大家深入了解这个版本添加哪些新特性使 PHP 更快、更可靠。

虽然 PHP 7.4 显著地提升了性能和提高代码可读性,PHP 8 才将会是 PHP 性能真正的里程碑,这在 JIT inclusion 的提案显示已充分证明。

现在去无偿迁移

总之,今天我们将概览 PHP 7.4 最瞩目的特性和性能提升。在继续探索之前,你最好记住以下重要的时间节点:

  • 6 月 6 日:PHP 7.4 Alpha 1

  • 7 月 18 日:PHP 7.4 Beta 1 – Feature freeze(特性固化)

  • 11 月 28 日:PHP 7.4 GA Release

你可从 the official RFC page 查看全部新特性和功能。

PHP 7.4 发布日期:

PHP 7.4 将于 2019 年 11 月 28 日发布。这是 PHP 7 的下一个小版本,会再次提升性能,提高代码的可读性和可维护性。

PHP 7.4 有什么新功能?

在这边文章中,我们将讨论 PHP 7.4 最终版本中应该增加一些变化和特性:

抛弃 array_merge :PHP 7.4 在数组表达式中引入了扩展运算符

从 PHP 5.6 开始,参数解析 是一种解析数组并遍历到参数列表中的语法。要解析一个或遍历一个数组,必须以 ...(三个点)作为前缀,如下所示:

function test(...$args) { var_dump($args); }
test(1, 2, 3);

现在  PHP 7.4 的 RFC 建议将这个功能扩展到数组定义中:

$arr = [...$args];

扩展操作符在数组表达式 第一个明显的优点是性能。RFC 文档:

扩展操作符应该比 array_merge 性能更好。不仅是因为扩展操作符是一种语言结构,array_merge 是一个函数,还因为可以优化编译常量数组的性能。

扩展操作符一个重要的优点是支持任何可遍历的对象, array_merge 函数只支持数组。

下面是数组表达式中的参数解析示例:

$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"
}

The Spread operator 提案以 43 票对 1 票获得通过。

箭头函数 2.0 (短闭包)

对于 PHP 而言,匿名函数 被认为十分冗长并且难以使用和维护的。RFC 提出了更短并且语法更简洁的 * 箭头函数(短闭包),能够在很大程度上使我们的 PHP 代码更简洁。

考虑如下例子:

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);

目前,要感谢 use 语法,匿名函数 (闭包) 可以从父作用域里继承已经定义的变量:

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

但是在 PHP 7.4 中, 在父作用域里定义的变量被隐式捕获(隐式作用域绑定)了。如此一来,我们可用只用一行代码重写整个上面的函数:

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

我们可以像使用 use(变量) 一样,直接使用在父作用域里定义的变量,并且它也不会修改父作用域的变量。

新的语法对我们构建更可读可维护的代码带来了极大的改善。我们也可以使用参数和返回类型、默认值、变长参数列表(可变函数),可以传递或返回引用等等。然后呢,短闭包还可以被用作类方法,可以像常规一样使用 $this

RFC 已经以 51 票对 8 票通过了,所以我们可以期待在 PHP 7.4 新增功能里见到它。

空合并赋值操作符

在 PHP 7 中,当我们需要同时使用三元运算符和 isset() 时,合并运算符(??)就可以派上用场了。如果第一个操作数是存在并且不为 NULL,则返回该操作数。否则返回第二个操作数。示例如下:

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

这段代码很简单:获取请求参数,如果不存在,则设置一个默认值。它的意思很明确,但如果出现像下方这个来自 RFC 中示例这种更长的变量名呢?

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

从长远的角度看,这段代码可能有点难以维护。因此,为了帮助开发人员编写更直观的代码,这个 RFC 建议引入空合并赋值操作符(??=)。因此,我们可以编写如下代码进行替代:

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

如果左侧的参数是 null,则使用右侧参数的值。请注意,当合并运算符是比较运算符时,??= 就是一个赋值运算符。

这项建议以 37:4 的票获得通过。

类型属性 2.0

参数类型声明(或类型提示)允许对将要传递给函数或者类方法的变量类型进行限定。该功能自 PHP 5 起可用,PHP 7.2 起可以使用对象作为数据类型。现在 PHP 7.4 通过添加 类属性类型声明 进一步扩展了类型提示。以下是一个基本的示例:

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

支持 void 与 callable 以外的所有类型

public int $scalarType;
protected ClassName $classType;
private ?ClassName $nullableClassType;

这项 RFC 解释了为什么不支持 void 和 callable 返回值的原因:

不支持 void 类型,因为它没有用到并且语义不明确。

不支持 callable 类型,因为其行为取决于上下文。

这样我们就可以安全地使用 boolintfloatstringarrayobjectiterableselfparent, 任何类或接口名称,并且可以为空 types (?type)。

类型可以用于静态属性:

public static iterable $staticProp;

也可以使用 var 标记:

var bool $flag;

可以设置默认属性值,当然必须与声明的属性类型匹配,但是只有可为空的属性可以具有默认的 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 已以 70 票对 1 票获得批准。

弱引用

在这项 RFC 中,PHP 7.4 引入了 WeakReference (弱引用) 类型,这样开发者就可以保留对对象的引用,而这不会阻止对象本身被破坏。

目前,PHP 通过使用诸如 pecl-weakref 之类的扩展名来支持弱引用。无论如何,新的 API 与记录的 WeakRef 类不同。

这是 一份简单的 demo 来自这项提议的作者 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 打印引用为 NULL,因为所引用的对象已被销毁。

该 RFC 以 28 票对 5 票获得通过。

协变量返回和协变量参数

方差 是类层次结构的一个属性,描述了类型构造函数的类型如何影响 subtypes。通常,类型构造函数可以是:

  • Invariant:如果超类型的类型约束子类型的类型。

  • Covariant:如果保留类型的顺序(类型从更具体到更一般)。

  • Contravariant:如果它颠倒了顺序(类型从更通用到更具体地排序)。

目前,PHP 的参数和返回类型大部分不变,只有少数例外。该 RFC 建议允许在参数类型和返回类型上进行协方差和协变,并提供一些代码示例。

这是 协变量返回 的一个简单例子:

interface Factory {
function make(): object;
}

class UserFactory implements Factory {
function make(): User;
}

这个是 协变量参数 一个示例:

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

class Collection implements Concatable {
// accepts all iterables, not just Iterator
function concat(iterable $input) {/* . . . */}
}

请参阅 RFC 以更详细地了解 PHP 7.4 协变量返回和协变量参数。

该 RFC 以 39 对 1 票获得通过。

预加载

这项提议 来自 Dmitry Stogov ,这是我们的受支持的提议之一,因为它可以显着提高 PHP 的性能。预加载 是在模块初始化时将库和框架加载到 OPCache 的过程,详细了解 [PHP 生命周期]。

PHP 生命周期 (资源镜像: PHP Internals)

用 Dmitry 的话来说,预加载是这样工作的:

在服务器启动时(在运行任何应用程序代码之前),我们可以将一组 PHP 文件加载到内存中,并使它们的内容 永久可用 给该服务器将服务的所有后续请求。与内部实体完全一样,这些文件中定义的所有函数和类也可用于开箱即用的请求。

这些文件在服务器启动时加载,在任何应用程序之前执行,并且对以后的任何请求均可用。就性能而言,这很棒。

Preloading is controlled by a specific php.ini directive: opcache.preload. This directive specifies a PHP script to be compiled and executed at server start-up. This file can be used to preload additional files, either including them or via the opcache_compile_file() function (read more on PHP documentation).
预加载由特定的 php.ini 指令控制:opcache.preload。该指令指定在服务器启动时要编译和执行的 PHP 脚本。此文件可用于预加载其他文件,包括它们或通过 opcache_compile_file() 函数(有关更多信息,请参见 [PHP 文档](https://www.php.net/manual/en/function.opc... -file.php))。

但是有一个缺点。实际上,RFC 里有明确声明:

预加载的文件将永远保留在 opcache 内存中。不重新启动另一台服务器,对其相应源文件的修改将不会生效。

但是,在预加载的文件中定义的所有函数将被永久加载到 PHP 函数和类表中,并且对于以后的每个请求均可用。即使这些改进可能有很大的不同,也会带来良好的性能改进。

您可以在官方的 预加载 RFC 页面 上阅读有关预加载的限制和例外的更多信息。

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

这是 Nikita Popov 的另一项提议

当前,我们有两种不同的机制可以在 PHP 中对对象进行自定义序列化:

  • __sleep() 和 __wakeup() 魔术方法

  • Serializable 接口

根据 Nikita 的说法,这两个选项都存在导致复杂且不可靠的代码的问题。您可以在 RFC 中深入研究此主题。在这里我只是提到新的序列化机制应该通过提供两种新的魔术方法__serialize() 和 __unserialize() 来解决这些问题,这两种方法结合了两个现有机制。

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

已废弃

PHP 7.4 不推荐使用以下功能。要获得更全面的弃用列表,请查看 PHP 7.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);

这是一个两步建议:

  • 从 7.4 版开始,PHP 在遇到带有 + ,- 和 . 的非括号表达式时应发出弃用通知。

  • 这些运算符的优先级的实际更改应在 PHP 8 中添加。

两项提议均以绝大多数票获得批准。

弃用左联想三元运算符

在 PHP 中,与许多其他语言不同,三元运算符是左关联的。根据 Nikita Popof 的说法,这对于在不同语言之间进行切换的开发者可能会造成混淆。

当前,在 PHP 中,以下代码是正确的:

$b = $a == 1 ? 'one' : $a == 2 ? 'two' : $a == 3 ? 'three' : 'other';

解释为:

$b = (($a == 1 ? 'one' : $a == 2) ? 'two' : $a == 3) ? 'three' : 'other';

这可能会导致错误,因为这可能不是我们打算要做的。因此,该 RFC 建议弃用并删除三元运算符的左关联性,并强制开发人员使用括号。

这是另外两个步骤的建议:

  • 从 PHP 7.4 开始,不显式使用括号的嵌套三元将抛出弃用警告。

  • 从 PHP 8.0 开始,将出现编译时错误。

该提案以 35 到 10 票获得批准。

在 Docker 中安装和运行 PHP 7.4

想在 Docker 上试试吗?幸运的是在 Docker 环境下你不需要再手动编译和配置 PHP 7.4 了 。如果你已经安装了 Docker , 那只需要花几秒钟安装这个非官方的 PHP-FPM 7.4 Docker 镜像 就可以在命令行中进行测试了。


如果你想要运行 PHP 7.4 的代码到你的浏览器中,那你还需要给 Docker 安装 Nginx 或 Apache 镜像。不用担心,只要按照 开发指南。将示例命令拷贝粘贴到命令行中并运行,就可以了。

摘要

在这篇文章中我们简单介绍了 PHP 7.4 发行版大量的更新和新增功能。如果你还想要了解完整的功能列表和正式的 RFC 官方文档,可以参考这些资源:

  • PHP 7.4 要求说明

  • PHP 7.4 升级说明

  • PHP 7.4 准备任务

这篇关于PHP 7.4 新特新速看,预加载了解一下~的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/935002

相关文章

SpringBoot中配置文件的加载顺序解读

《SpringBoot中配置文件的加载顺序解读》:本文主要介绍SpringBoot中配置文件的加载顺序,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录SpringBoot配置文件的加载顺序1、命令⾏参数2、Java系统属性3、操作系统环境变量5、项目【外部】的ap

一文详解Java异常处理你都了解哪些知识

《一文详解Java异常处理你都了解哪些知识》:本文主要介绍Java异常处理的相关资料,包括异常的分类、捕获和处理异常的语法、常见的异常类型以及自定义异常的实现,文中通过代码介绍的非常详细,需要的朋... 目录前言一、什么是异常二、异常的分类2.1 受检异常2.2 非受检异常三、异常处理的语法3.1 try-

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

一文带你了解SpringBoot中启动参数的各种用法

《一文带你了解SpringBoot中启动参数的各种用法》在使用SpringBoot开发应用时,我们通常需要根据不同的环境或特定需求调整启动参数,那么,SpringBoot提供了哪些方式来配置这些启动参... 目录一、启动参数的常见传递方式二、通过命令行参数传递启动参数三、使用 application.pro

SpringBoot项目启动报错"找不到或无法加载主类"的解决方法

《SpringBoot项目启动报错找不到或无法加载主类的解决方法》在使用IntelliJIDEA开发基于SpringBoot框架的Java程序时,可能会出现找不到或无法加载主类com.example.... 目录一、问题描述二、排查过程三、解决方案一、问题描述在使用 IntelliJ IDEA 开发基于

一文带你深入了解Python中的GeneratorExit异常处理

《一文带你深入了解Python中的GeneratorExit异常处理》GeneratorExit是Python内置的异常,当生成器或协程被强制关闭时,Python解释器会向其发送这个异常,下面我们来看... 目录GeneratorExit:协程世界的死亡通知书什么是GeneratorExit实际中的问题案例

Android WebView无法加载H5页面的常见问题和解决方法

《AndroidWebView无法加载H5页面的常见问题和解决方法》AndroidWebView是一种视图组件,使得Android应用能够显示网页内容,它基于Chromium,具备现代浏览器的许多功... 目录1. WebView 简介2. 常见问题3. 网络权限设置4. 启用 JavaScript5. D

SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法

《SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法》本文主要介绍了SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法,具有一定的参考价值,感兴趣的可以了解一下... 目录方法1:更改IDE配置方法2:在Eclipse中清理项目方法3:使用Maven命令行在开发Sprin

spring-boot-starter-thymeleaf加载外部html文件方式

《spring-boot-starter-thymeleaf加载外部html文件方式》本文介绍了在SpringMVC中使用Thymeleaf模板引擎加载外部HTML文件的方法,以及在SpringBoo... 目录1.Thymeleaf介绍2.springboot使用thymeleaf2.1.引入spring

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明