PHP 7.4 ,下一个 PHP 7 较小的发布版,指望在 2019 年 11 月 28 日发布。所以,如今是时候让你们深刻了解这个版本添加哪些新特性使 PHP 更快、更可靠。
虽然 PHP 7.4 显著地提高了性能和提升代码可读性,PHP 8 才将会是 PHP 性能真正的里程碑,这在 JIT inclusion 的提案显示已充分证实。
如今去无偿迁移php
总之,今天咱们将概览 PHP 7.4 最瞩目的特性和性能提高。在继续探索以前,你最好记住如下重要的时间节点:html
你可从 the official RFC page 查看所有新特性和功能。git
QQ交流群github
PHP 7.4 将于 2019 年 11 月 28 日发布。这是 PHP 7 的下一个小版本,会再次提高性能,提升代码的可读性和可维护性。docker
在这边文章中,咱们将讨论 PHP 7.4 最终版本中应该增长一些变化和特性:数组
从 PHP 5.6 开始,参数解析 是一种解析数组并遍历到参数列表中的语法。要解析一个或遍历一个数组,必须以 ...(三个点)做为前缀,以下所示:浏览器
function test(...$args) { var_dump($args); }
test(1, 2, 3);复制代码
如今 PHP 7.4 的 RFC 建议将这个功能扩展到数组定义中:安全
$arr = [...$args];复制代码
扩展操做符在数组表达式 第一个明显的优势是性能。RFC 文档:bash
扩展操做符应该比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 票得到经过。
对于 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 的票数比例得到经过。
参数类型声明(或类型提示)容许对将要传递给函数或者类方法的变量类型进行限定。该功能自 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
类型,由于其行为取决于上下文。
这样咱们就能够安全地使用 bool
, int
, float
, string
, array
, object
, iterable
, self
, parent
, 任何类或接口名称,而且能够为空 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。 一般,类型构造函数能够是:
目前,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 文件加载到内存中,并使它们的内容
永久可用
给该服务器将服务的全部后续请求。 与内部实体彻底同样,这些文件中定义的全部函数和类也可用于开箱即用的请求。
这些文件在服务器启动时加载,在任何应用程序以前执行,而且对之后的任何请求都可用。 就性能而言,这很棒。
预加载由特定的 php.ini
指令控制:opcache.preload
。 该指令指定在服务器启动时要编译和执行的 PHP 脚本。 此文件可用于预加载其余文件,包括它们或经过 opcache_compile_file()
函数(有关更多信息,请参见 [PHP 文档](www.php.net/manual/en/f… -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);复制代码
这是一个两步建议:
+
,-
和 .
的非括号表达式时应发出弃用通知。两项提议均以绝大多数票得到批准。
在 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 建议弃用并删除三元运算符的左关联性,并强制开发人员使用括号。
这是另外两个步骤的建议:
该提案以 35 到 10 票得到批准。
想在 Docker 上试试吗?幸运的是在 Docker 环境下你不须要再手动编译和配置 PHP 7.4 了 。若是你已经安装了 Docker , 那只须要花几秒钟安装这个非官方的 PHP-FPM 7.4 Docker 镜像 就能够在命令行中进行测试了。
若是你想要运行 PHP 7.4 的代码到你的浏览器中,那你还须要给 Docker 安装 Nginx 或 Apache 镜像。不用担忧,只要按照开发指南。 将示例命令拷贝粘贴到命令行中并运行,就能够了。
但愿以上内容能帮助到你们,若是喜欢个人文章,想与一群资深开发者一块儿交流学习的话,获取更多学习资料欢迎加入个人学习交流群677079770一块儿学习成长,一样也能够关注一下个人专栏。谢谢~