编程语言/PHP PHP7各个版本新增特性 PHP从5.6 跳过6直接来到7,带来新的语言特性,更带来性能很大飞越。根据w3techs统计截止截止2019年5月18月有79%网站使用PHP做为服务端开发语言,这些网站使用的PHP版本统计如下: {% iframe https://export.cyub.vip/i?all=%7B%22chart%22%3A%7B%22plotBackgroundColor%22%3Anull%2C%22plotBorderWidth%22%3Anull%2C%22plotShadow%22%3Afalse%2C%22type%22%3A%22pie%22%7D%2C%22title%22%3A%7B%22text%22%3A%22PHP%E7%89%88%E6%9C%AC%E4%BD%BF%E7%94%A8%E5%88%86%E5%B8%83%22%7D%2C%22tooltip%22%3A%7B%22pointFormat%22%3A%22%7Bseries.name%7D%3A%20%3Cb%3E%7Bpoint.percentage%3A.1f%7D%25%3C%2Fb%3E%22%7D%2C%22plotOptions%22%3A%7B%22pie%22%3A%7B%22allowPointSelect%22%3Atrue%2C%22cursor%22%3A%22pointer%22%2C%22dataLabels%22%3A%7B%22enabled%22%3Atrue%2C%22format%22%3A%22%3Cb%3E%7Bpoint.name%7D%3C%2Fb%3E%3A%20%7Bpoint.percentage%3A.1f%7D%20%25%22%7D%7D%7D%2C%22series%22%3A%5B%7B%22name%22%3A%22Version%22%2C%22colorByPoint%22%3Atrue%2C%22data%22%3A%5B%7B%22name%22%3A%22Version%205%22%2C%22y%22%3A66.9%7D%2C%7B%22name%22%3A%22Version%207%22%2C%22y%22%3A32.5%2C%22color%22%3A%22%23e4d354%22%7D%2C%7B%22name%22%3A%22Version%204%22%2C%22y%22%3A0.6%7D%2C%7B%22name%22%3A%22Version%203%22%2C%22y%22%3A0.1%7D%5D%7D%5D%7D&width=490&height=360 %} <!-- more --> 其中PHP 5 和 PHP 7细化分布下: <iframe src="https://export.cyub.vip/i?all=%7B%22chart%22%3A%7B%22plotBackgroundColor%22%3Anull%2C%22plotBorderWidth%22%3Anull%2C%22plotShadow%22%3Afalse%2C%22type%22%3A%22pie%22%7D%2C%22title%22%3A%7B%22text%22%3A%22PHP7%20%E7%89%88%E6%9C%AC%E4%BD%BF%E7%94%A8%E5%88%86%E5%B8%83%22%7D%2C%22tooltip%22%3A%7B%22pointFormat%22%3A%22%7Bseries.name%7D%3A%20%3Cb%3E%7Bpoint.percentage%3A.1f%7D%25%3C%2Fb%3E%22%7D%2C%22plotOptions%22%3A%7B%22pie%22%3A%7B%22allowPointSelect%22%3Atrue%2C%22cursor%22%3A%22pointer%22%2C%22dataLabels%22%3A%7B%22enabled%22%3Atrue%2C%22format%22%3A%22%3Cb%3E%7Bpoint.name%7D%3C%2Fb%3E%3A%20%7Bpoint.percentage%3A.1f%7D%20%25%22%7D%7D%7D%2C%22series%22%3A%5B%7B%22name%22%3A%22Version%22%2C%22colorByPoint%22%3Atrue%2C%22data%22%3A%5B%7B%22name%22%3A%22PHP%207.2%22%2C%22y%22%3A34.3%7D%2C%7B%22name%22%3A%22PHP%207.0%22%2C%22y%22%3A33.6%2C%22color%22%3A%22%23e4d354%22%7D%2C%7B%22name%22%3A%22PHP%207.1%22%2C%22y%22%3A26.9%7D%2C%7B%22name%22%3A%22PHP%207.3%22%2C%22y%22%3A5.2%7D%2C%7B%22name%22%3A%22PHP%207.4%22%2C%22y%22%3A0.1%7D%5D%7D%5D%7D&width=490&height=360" width="490" height="370" overflow="hide" frameborder="0"> {% iframe https://export.cyub.vip/i %} <iframe src="https://export.cyub.vip/i?all=%7B%22chart%22%3A%7B%22plotBackgroundColor%22%3Anull%2C%22plotBorderWidth%22%3Anull%2C%22plotShadow%22%3Afalse%2C%22type%22%3A%22pie%22%7D%2C%22title%22%3A%7B%22text%22%3A%22PHP5%20%E7%89%88%E6%9C%AC%E4%BD%BF%E7%94%A8%E5%88%86%E5%B8%83%22%7D%2C%22tooltip%22%3A%7B%22pointFormat%22%3A%22%7Bseries.name%7D%3A%20%3Cb%3E%7Bpoint.percentage%3A.1f%7D%25%3C%2Fb%3E%22%7D%2C%22plotOptions%22%3A%7B%22pie%22%3A%7B%22allowPointSelect%22%3Atrue%2C%22cursor%22%3A%22pointer%22%2C%22dataLabels%22%3A%7B%22enabled%22%3Atrue%2C%22format%22%3A%22%3Cb%3E%7Bpoint.name%7D%3C%2Fb%3E%3A%20%7Bpoint.percentage%3A.1f%7D%20%25%22%7D%7D%7D%2C%22series%22%3A%5B%7B%22name%22%3A%22Version%22%2C%22colorByPoint%22%3Atrue%2C%22data%22%3A%5B%7B%22name%22%3A%22PHP%205.6%22%2C%22y%22%3A45.5%7D%2C%7B%22name%22%3A%22PHP%205.4%22%2C%22y%22%3A19.1%2C%22color%22%3A%22%23e4d354%22%7D%2C%7B%22name%22%3A%22PHP%205.3%22%2C%22y%22%3A15.6%7D%2C%7B%22name%22%3A%22PHP%205.5%22%2C%22y%22%3A12.9%7D%2C%7B%22name%22%3A%22PHP%205.2%22%2C%22y%22%3A6.5%7D%2C%7B%22name%22%3A%22PHP%205.1%22%2C%22y%22%3A0.4%7D%2C%7B%22name%22%3A%22PHP%205.0%22%2C%22y%22%3A0.1%7D%2C%7B%22name%22%3A%22PHP%205.7%22%2C%22y%22%3A0.1%7D%5D%7D%5D%7D&width=490&height=360" width="490" height="370" overflow="hide" frameborder="0"> {% iframe https://export.cyub.vip/i %} 这里我们不探讨性能提升方面,只是看看PHP7带来了哪些语言上的新特性。下面是PHP7各个版本新增特性详细说明: ## 7.0.x ### 新特性 #### null合并运算符 PHP 5中我们常使用isset和三目运算符来判断变量是否存在,PHP 7开始可以使null合并运算符(??),如果变量存在且值不为NULL,则返回自身的值,否则返回它的第二个操作数。 <div class="language-text highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><?php </span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a> </span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>$x = NULL; </span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a>$y = NULL; </span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a>$z = 3; </span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a>var_dump($x ?? $y ?? $z); // int(3) </span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a> </span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a>$x = ["c" => "meaningful_value"]; </span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a>var_dump($x["a"] ?? $x["b"] ?? $x["c"]); // string(16) "meaningful_value" </span></code></pre></div> #### 太空船操作符 太空船操作符(<=>),用于两个表达式,当$a小于、等于或者大于$b时,分别返回-1、0、1 <div class="language-text highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a>$array = [1, 2, 3, 4, 6]; </span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a>// PHP 5 </span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a>usort($array, function ($a, $b) { </span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a> return ($a < $b) ? -1 : ($a = $b ? 0 : 1); </span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a>}); </span><span id="__span-1-6"><a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a> </span><span id="__span-1-7"><a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a>// PHP 7 </span><span id="__span-1-8"><a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a>usort($array, function ($a, $b) { </span><span id="__span-1-9"><a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a> return $a <=> $b; </span><span id="__span-1-10"><a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a>}); </span></code></pre></div> #### 新增整数除法函数intdiv() intdiv用于整数的除法运算 <div class="language-text highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><?php </span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a> </span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a>var_dump(intdiv(10, 3)); // int(3) </span></code></pre></div> #### 标量参数类型声明 PHP 5也支持参数类型声明,但它只支持复合变量类型声明,比如类或数组声明。PHP 7 开始之后支持int,bool等标量类型声明了。具体支持支持类型如下: 类型 | 描述 | 最低 PHP版本 ---|--- | ---- class/interface name | 参数必须是类或者接口的一个实例 | PHP 5.0.0 self | 参数必须是当前类的实例 | PHP 5.0.0 array | 参数必须是一个数组 | PHP 5.1.0 callable | 参数必须是一个[可回调类型](https://www.php.net/manual/zh/language.types.callable.php) | PHP 5.4.0 bool | 参数必须布尔类型 | PHP 7.0.0 float | 参数必须是浮点类型 | PHP 7.0.0 int | 参数必须是整数类型 | PHP 7.0.0 string | 参数必须是字符串类型 | PHP 7.0.0 #### 返回值类型声明 返回类型声明指明了函数返回值的类型。可用的类型与参数声明中可用的类型相同, 见上表 <div class="language-text highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><?php </span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a> </span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a>interface A { </span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a> static function make(): A; </span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a>} </span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a>class B implements A { </span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a> static function make(): A { </span><span id="__span-3-8"><a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a> return new B(); </span><span id="__span-3-9"><a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a> } </span><span id="__span-3-10"><a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a>} </span></code></pre></div> #### 通过define()定义常量数组 PHP 5.6中只能通过const定义数组常量,现在可以通过define()来定以 <div class="language-text highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><?php </span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a>define('ANIMALS', [ </span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a> 'dog', </span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a> 'cat', </span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a> 'bird' </span><span id="__span-4-6"><a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a>]); </span><span id="__span-4-7"><a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a> </span><span id="__span-4-8"><a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a>echo ANIMALS[1]; // 输出 "cat" </span></code></pre></div> #### 匿名类 PHP 7 开始支持同 new class 来实例化一个匿名类, <div class="language-text highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><?php </span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a> </span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a>$di = new DI(); </span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a> </span><span id="__span-5-5"><a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a>$di->setLogger(new class { </span><span id="__span-5-6"><a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a> public function log(string $msg) { </span><span id="__span-5-7"><a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a> echo $msg; </span><span id="__span-5-8"><a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a> } </span><span id="__span-5-9"><a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a> } </span><span id="__span-5-10"><a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a>}) </span></code></pre></div> #### Closure::call() Closure::call() 用于绑定一个方法到对象上闭包并调用它,并有着更好的性能 <div class="language-text highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><?php </span></code></pre></div> ### 变更 #### 错误和异常处理 PHP 7 起大部分错误可以被作为Error异常抛出。PHP 5 使用错误报告等来处理错误, 可参看[PHP错误与异常处理详解(一)](https://www.cyub.vip/2018/05/17/PHP%E9%94%99%E8%AF%AF%E4%B8%8E%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E8%AF%A6%E8%A7%A3%EF%BC%88%E4%B8%80%EF%BC%89/)。 PHP 7 抛出的Error 可以通过catch(Error $e) {}来捕获或注册异常处理函数set_exception_handler来捕获。所有异常和错误类都实现了Throwalble接口。 Error的层次接口结构: - Throwable - Error - ArithmeticError - DivisionByZeroError - DivisionByZeroError - AssertionError - ParseError - TypeError - ArgumentCountError - Exception - ClosedGeneratorException - DOMException - ErrorException - IntlException - LogicException - BadFunctionCallException - BadMethodCallException - DomainException - InvalidArgumentException - LengthException - OutOfRangeException - PharException - ReflectionException - RuntimeException - OutOfBoundsException - OverflowException - PDOException - RangeException - UnderflowException - UnexpectedValueException `set_exception_handler()`接收的对象不一定是Exception对象,有可能是Error对象 <div class="language-text highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>// PHP 5 时代代码 </span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a>func handler(Excetion $e) { ... } // 如果此时接受到Error对象,将会导致fatal error </span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a>set_exception_handler('handler') </span><span id="__span-7-4"><a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a> </span><span id="__span-7-5"><a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a>// 兼容PHP 5 和 7 </span><span id="__span-7-6"><a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a>function handler($e) {...} </span><span id="__span-7-7"><a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a> </span><span id="__span-7-8"><a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a>// 仅支持 PHP 7 </span><span id="__span-7-9"><a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a>function handler(Throwalbe $e) { ... } </span></code></pre></div> #### foreach变化 ##### 循环时候不在改变内部数组指针 PHP 7之前,当数组通过foreach 迭代时候,数组指针会移动。 <div class="language-text highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><?php </span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a>$array = [0, 1, 2]; </span><span id="__span-8-3"><a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a>foreach ($array as &$val) { </span><span id="__span-8-4"><a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a>} </span><span id="__span-8-5"><a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a> </span><span id="__span-8-6"><a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a>var_dump(current($array); // php 5 输出 bool(false); php 7 输出int(1) </span></code></pre></div> ##### 通过引用遍历时候,能够动态更该遍历 <div class="language-text highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><?php </span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a>$array = [0]; </span><span id="__span-9-3"><a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a>foreach ($array as &$val) { // 注意此处一定是引用遍历,否则没有效果 </span><span id="__span-9-4"><a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a> var_dump($val); </span><span id="__span-9-5"><a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a> $array[1] = 1; </span><span id="__span-9-6"><a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a>} </span></code></pre></div> PHP 5 输出: <div class="language-text highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a>int(0) </span></code></pre></div> PHP 7 输出: <div class="language-text highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a>int(0) </span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a>int(1) </span></code></pre></div> 注意PHP 5 和 PHP 7最后的数组$array都会多一个元素1 <div class="language-text highlight"><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><?php </span><span id="__span-12-2"><a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a> </span><span id="__span-12-3"><a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a>$array = [0, 1]; </span></code></pre></div> 更多PHP 7.0.x 变更与新特性见[从PHP 5.6.x 移植到 PHP 7.0.x](https://www.php.net/manual/zh/migration70.php) #### 性能的提升与内存使用减少 PHP 7速度相比 5.6提升了2倍  内存使用显著下降  ## 7.1.x ### 新特性 #### 可为空(Nullable)类型 参数类型和返回值类型支持可为空类型。当在类型前面加一个问,传入的参数或函数返回值要么是该类型,要么是null <div class="language-text highlight"><pre><span></span><code><span id="__span-13-1"><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><?php </span><span id="__span-13-2"><a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a> </span><span id="__span-13-3"><a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a>function answer(): ?int { </span><span id="__span-13-4"><a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a> return null; //ok </span><span id="__span-13-5"><a id="__codelineno-13-5" name="__codelineno-13-5" href="#__codelineno-13-5"></a>} </span><span id="__span-13-6"><a id="__codelineno-13-6" name="__codelineno-13-6" href="#__codelineno-13-6"></a> </span><span id="__span-13-7"><a id="__codelineno-13-7" name="__codelineno-13-7" href="#__codelineno-13-7"></a>function answer(): ?int { </span><span id="__span-13-8"><a id="__codelineno-13-8" name="__codelineno-13-8" href="#__codelineno-13-8"></a> return 42; // ok </span><span id="__span-13-9"><a id="__codelineno-13-9" name="__codelineno-13-9" href="#__codelineno-13-9"></a>} </span><span id="__span-13-10"><a id="__codelineno-13-10" name="__codelineno-13-10" href="#__codelineno-13-10"></a> </span><span id="__span-13-11"><a id="__codelineno-13-11" name="__codelineno-13-11" href="#__codelineno-13-11"></a>function answer(): ?int { </span><span id="__span-13-12"><a id="__codelineno-13-12" name="__codelineno-13-12" href="#__codelineno-13-12"></a> return new stdclass(); // error </span><span id="__span-13-13"><a id="__codelineno-13-13" name="__codelineno-13-13" href="#__codelineno-13-13"></a>} </span><span id="__span-13-14"><a id="__codelineno-13-14" name="__codelineno-13-14" href="#__codelineno-13-14"></a>function say(?string $msg) { </span><span id="__span-13-15"><a id="__codelineno-13-15" name="__codelineno-13-15" href="#__codelineno-13-15"></a> if ($msg) { </span><span id="__span-13-16"><a id="__codelineno-13-16" name="__codelineno-13-16" href="#__codelineno-13-16"></a> echo $msg; </span><span id="__span-13-17"><a id="__codelineno-13-17" name="__codelineno-13-17" href="#__codelineno-13-17"></a> } </span><span id="__span-13-18"><a id="__codelineno-13-18" name="__codelineno-13-18" href="#__codelineno-13-18"></a>} </span><span id="__span-13-19"><a id="__codelineno-13-19" name="__codelineno-13-19" href="#__codelineno-13-19"></a> </span><span id="__span-13-20"><a id="__codelineno-13-20" name="__codelineno-13-20" href="#__codelineno-13-20"></a>say('hello'); // ok -- prints hello </span><span id="__span-13-21"><a id="__codelineno-13-21" name="__codelineno-13-21" href="#__codelineno-13-21"></a>say(null); // ok -- does not print </span><span id="__span-13-22"><a id="__codelineno-13-22" name="__codelineno-13-22" href="#__codelineno-13-22"></a>say(); // error -- missing parameter </span><span id="__span-13-23"><a id="__codelineno-13-23" name="__codelineno-13-23" href="#__codelineno-13-23"></a>say(new stdclass); //error -- bad type </span></code></pre></div> #### void类型返回值类型 一个新的返回值类型void被引入。 返回值声明为 void 类型的方法要么干脆省去 return 语句,要么使用一个空的 return 语句。 对于 void 函数来说,NULL 不是一个合法的返回值,试图去获取void方法的返回值会得到NULL <div class="language-text highlight"><pre><span></span><code><span id="__span-14-1"><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a><?php </span><span id="__span-14-2"><a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a>function swap(&$left, &$right) : void </span><span id="__span-14-3"><a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a>{ </span><span id="__span-14-4"><a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a> if ($left === $right) { </span><span id="__span-14-5"><a id="__codelineno-14-5" name="__codelineno-14-5" href="#__codelineno-14-5"></a> return; </span><span id="__span-14-6"><a id="__codelineno-14-6" name="__codelineno-14-6" href="#__codelineno-14-6"></a> } </span><span id="__span-14-7"><a id="__codelineno-14-7" name="__codelineno-14-7" href="#__codelineno-14-7"></a> </span><span id="__span-14-8"><a id="__codelineno-14-8" name="__codelineno-14-8" href="#__codelineno-14-8"></a> $tmp = $left; </span><span id="__span-14-9"><a id="__codelineno-14-9" name="__codelineno-14-9" href="#__codelineno-14-9"></a> $left = $right; </span><span id="__span-14-10"><a id="__codelineno-14-10" name="__codelineno-14-10" href="#__codelineno-14-10"></a> $right = $tmp; </span><span id="__span-14-11"><a id="__codelineno-14-11" name="__codelineno-14-11" href="#__codelineno-14-11"></a>} </span><span id="__span-14-12"><a id="__codelineno-14-12" name="__codelineno-14-12" href="#__codelineno-14-12"></a> </span><span id="__span-14-13"><a id="__codelineno-14-13" name="__codelineno-14-13" href="#__codelineno-14-13"></a>$a = 1; </span><span id="__span-14-14"><a id="__codelineno-14-14" name="__codelineno-14-14" href="#__codelineno-14-14"></a>$b = 2; </span><span id="__span-14-15"><a id="__codelineno-14-15" name="__codelineno-14-15" href="#__codelineno-14-15"></a>var_dump(swap($a, $b), $a, $b); </span></code></pre></div> 上面程序会输出: <div class="language-text highlight"><pre><span></span><code><span id="__span-15-1"><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a>null </span><span id="__span-15-2"><a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a>int(2) </span><span id="__span-15-3"><a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a>int(1) </span></code></pre></div> #### iterable类型 iterable类型可用于参数类型提示,或者返回值类型提示,表明参数或返回值是一个数组或者实现了`Traversable`接口的对象。 iterable类型可用于foreach循环。 <div class="language-text highlight"><pre><span></span><code><span id="__span-16-1"><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a><?php </span><span id="__span-16-2"><a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a>function foo(iterable $iterable) { </span><span id="__span-16-3"><a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a> foreach ($iterable as $value) { </span><span id="__span-16-4"><a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a> // ... </span><span id="__span-16-5"><a id="__codelineno-16-5" name="__codelineno-16-5" href="#__codelineno-16-5"></a> } </span><span id="__span-16-6"><a id="__codelineno-16-6" name="__codelineno-16-6" href="#__codelineno-16-6"></a>} </span></code></pre></div> #### 数组解构赋值 结构赋值实现list()类似功能 <div class="language-text highlight"><pre><span></span><code><span id="__span-17-1"><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><?php </span><span id="__span-17-2"><a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a>$array = [1, 2, 3]; </span><span id="__span-17-3"><a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a>[$a, $b, $c] = $array; </span><span id="__span-17-4"><a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a>// 效果跟list($a, $b, $c) = $array; 一样 </span><span id="__span-17-5"><a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a> </span><span id="__span-17-6"><a id="__codelineno-17-6" name="__codelineno-17-6" href="#__codelineno-17-6"></a>// 支持键名 </span><span id="__span-17-7"><a id="__codelineno-17-7" name="__codelineno-17-7" href="#__codelineno-17-7"></a>$array = ['a' => 1, 'b' => 2, 'c' => 3]; </span><span id="__span-17-8"><a id="__codelineno-17-8" name="__codelineno-17-8" href="#__codelineno-17-8"></a>["a" => $a, "b" => $b, "c" => $c] = $array; </span><span id="__span-17-9"><a id="__codelineno-17-9" name="__codelineno-17-9" href="#__codelineno-17-9"></a> </span><span id="__span-17-10"><a id="__codelineno-17-10" name="__codelineno-17-10" href="#__codelineno-17-10"></a>$data = [ </span><span id="__span-17-11"><a id="__codelineno-17-11" name="__codelineno-17-11" href="#__codelineno-17-11"></a> [1, 'Tom'], </span><span id="__span-17-12"><a id="__codelineno-17-12" name="__codelineno-17-12" href="#__codelineno-17-12"></a> [2, 'Fred'], </span><span id="__span-17-13"><a id="__codelineno-17-13" name="__codelineno-17-13" href="#__codelineno-17-13"></a>]; </span><span id="__span-17-14"><a id="__codelineno-17-14" name="__codelineno-17-14" href="#__codelineno-17-14"></a>foreach ($data as list($id, $name)) { </span><span id="__span-17-15"><a id="__codelineno-17-15" name="__codelineno-17-15" href="#__codelineno-17-15"></a>} </span><span id="__span-17-16"><a id="__codelineno-17-16" name="__codelineno-17-16" href="#__codelineno-17-16"></a> </span><span id="__span-17-17"><a id="__codelineno-17-17" name="__codelineno-17-17" href="#__codelineno-17-17"></a>foreach ($data as [$id, $name]) { </span><span id="__span-17-18"><a id="__codelineno-17-18" name="__codelineno-17-18" href="#__codelineno-17-18"></a>} </span></code></pre></div> #### list()增强支持键名 <div class="language-text highlight"><pre><span></span><code><span id="__span-18-1"><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a><?php </span><span id="__span-18-2"><a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a>$array = ['a' => 1, 'b' => 2, 'c' => 3]; </span><span id="__span-18-3"><a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a>list("a" => $a, "b" => $b, "c" => $c) = $array; </span></code></pre></div> #### 支持捕获多个类型 <div class="language-text highlight"><pre><span></span><code><span id="__span-19-1"><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><?php </span><span id="__span-19-2"><a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a> </span><span id="__span-19-3"><a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a>try { </span><span id="__span-19-4"><a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a> // Some code... </span><span id="__span-19-5"><a id="__codelineno-19-5" name="__codelineno-19-5" href="#__codelineno-19-5"></a>} catch (ExceptionType1 | ExceptionType2 $e) { </span><span id="__span-19-6"><a id="__codelineno-19-6" name="__codelineno-19-6" href="#__codelineno-19-6"></a> // Code to handle the exception </span><span id="__span-19-7"><a id="__codelineno-19-7" name="__codelineno-19-7" href="#__codelineno-19-7"></a>} catch (\Exception $e) { </span><span id="__span-19-8"><a id="__codelineno-19-8" name="__codelineno-19-8" href="#__codelineno-19-8"></a> // ... </span><span id="__span-19-9"><a id="__codelineno-19-9" name="__codelineno-19-9" href="#__codelineno-19-9"></a>} </span></code></pre></div> #### 支持负的字符串偏移量 一个负数的偏移量表明从字符串结尾开始的偏移量 <div class="language-text highlight"><pre><span></span><code><span id="__span-20-1"><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a><?php </span><span id="__span-20-2"><a id="__codelineno-20-2" name="__codelineno-20-2" href="#__codelineno-20-2"></a>var_dump("abcdef"[-2]); </span><span id="__span-20-3"><a id="__codelineno-20-3" name="__codelineno-20-3" href="#__codelineno-20-3"></a>var_dump(strpos("aabbcc", "b", -3)); </span></code></pre></div> 上面程序将会输出 <div class="language-text highlight"><pre><span></span><code><span id="__span-21-1"><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a>string (1) "e" </span><span id="__span-21-2"><a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a>int(3) </span></code></pre></div> #### is_iterable()验证变量是否是可迭代类型 is_iterable用来验证变量是否是iterable伪类类型 <div class="language-text highlight"><pre><span></span><code><span id="__span-22-1"><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a><?php </span><span id="__span-22-2"><a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a>var_dump(is_iterable([1, 2, 3])); // bool(true) </span><span id="__span-22-3"><a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a>var_dump(is_iterable(new ArrayIterator([1, 2, 3]))); // bool(true) </span><span id="__span-22-4"><a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a>var_dump(is_iterable((function () { yield 1; })())); // bool(true) </span><span id="__span-22-5"><a id="__codelineno-22-5" name="__codelineno-22-5" href="#__codelineno-22-5"></a>var_dump(is_iterable(1)); // bool(false) </span><span id="__span-22-6"><a id="__codelineno-22-6" name="__codelineno-22-6" href="#__codelineno-22-6"></a>var_dump(is_iterable(new stdClass())); // bool(false) </span></code></pre></div> ## 7.2.x ### 对象类型 对象类型用于输入参数和函数返回值都是任何对象乐西 <div class="language-text highlight"><pre><span></span><code><span id="__span-23-1"><a id="__codelineno-23-1" name="__codelineno-23-1" href="#__codelineno-23-1"></a><?php </span><span id="__span-23-2"><a id="__codelineno-23-2" name="__codelineno-23-2" href="#__codelineno-23-2"></a> </span><span id="__span-23-3"><a id="__codelineno-23-3" name="__codelineno-23-3" href="#__codelineno-23-3"></a>function test(object $obj) : object </span><span id="__span-23-4"><a id="__codelineno-23-4" name="__codelineno-23-4" href="#__codelineno-23-4"></a>{ </span><span id="__span-23-5"><a id="__codelineno-23-5" name="__codelineno-23-5" href="#__codelineno-23-5"></a> return new SplQueue(); </span><span id="__span-23-6"><a id="__codelineno-23-6" name="__codelineno-23-6" href="#__codelineno-23-6"></a>} </span><span id="__span-23-7"><a id="__codelineno-23-7" name="__codelineno-23-7" href="#__codelineno-23-7"></a> </span><span id="__span-23-8"><a id="__codelineno-23-8" name="__codelineno-23-8" href="#__codelineno-23-8"></a>test(new StdClass()); </span></code></pre></div> ### 参数类型拓展 重写方法和接口实现的参数类型可以使任意类型,即使父类方法指定一个固定的参数类型 <div class="language-text highlight"><pre><span></span><code><span id="__span-24-1"><a id="__codelineno-24-1" name="__codelineno-24-1" href="#__codelineno-24-1"></a><?php </span><span id="__span-24-2"><a id="__codelineno-24-2" name="__codelineno-24-2" href="#__codelineno-24-2"></a> </span><span id="__span-24-3"><a id="__codelineno-24-3" name="__codelineno-24-3" href="#__codelineno-24-3"></a>interface A </span><span id="__span-24-4"><a id="__codelineno-24-4" name="__codelineno-24-4" href="#__codelineno-24-4"></a>{ </span><span id="__span-24-5"><a id="__codelineno-24-5" name="__codelineno-24-5" href="#__codelineno-24-5"></a> public function Test(array $input); </span><span id="__span-24-6"><a id="__codelineno-24-6" name="__codelineno-24-6" href="#__codelineno-24-6"></a>} </span><span id="__span-24-7"><a id="__codelineno-24-7" name="__codelineno-24-7" href="#__codelineno-24-7"></a> </span><span id="__span-24-8"><a id="__codelineno-24-8" name="__codelineno-24-8" href="#__codelineno-24-8"></a>class B implements A </span><span id="__span-24-9"><a id="__codelineno-24-9" name="__codelineno-24-9" href="#__codelineno-24-9"></a>{ </span><span id="__span-24-10"><a id="__codelineno-24-10" name="__codelineno-24-10" href="#__codelineno-24-10"></a> public function Test($input){} // type omitted for $input </span><span id="__span-24-11"><a id="__codelineno-24-11" name="__codelineno-24-11" href="#__codelineno-24-11"></a>} </span></code></pre></div> 更多新特性与变更见[从PHP 7.1.x 移植到 PHP 7.2.x ](https://www.php.net/manual/zh/migration72.php) ## 7.3.x ### json_decode()抛出异常 json_decode()第二个参数传入`JSON_THROW_ON_ERROR`,那么当json解析失败是,会抛出`JsonException`异常 7.2之前(含7.2)的获取json解析错误使用如下方法: <div class="language-text highlight"><pre><span></span><code><span id="__span-25-1"><a id="__codelineno-25-1" name="__codelineno-25-1" href="#__codelineno-25-1"></a><?php </span><span id="__span-25-2"><a id="__codelineno-25-2" name="__codelineno-25-2" href="#__codelineno-25-2"></a> </span><span id="__span-25-3"><a id="__codelineno-25-3" name="__codelineno-25-3" href="#__codelineno-25-3"></a>json_decode("{"); </span><span id="__span-25-4"><a id="__codelineno-25-4" name="__codelineno-25-4" href="#__codelineno-25-4"></a>json_last_error() === JSON_ERROR_NONE // 结果是false </span><span id="__span-25-5"><a id="__codelineno-25-5" name="__codelineno-25-5" href="#__codelineno-25-5"></a>echo json_last_error_msg() // 输出 "Syntax error" </span></code></pre></div> 7.3起我们可以捕获json处理异常了: <div class="language-text highlight"><pre><span></span><code><span id="__span-26-1"><a id="__codelineno-26-1" name="__codelineno-26-1" href="#__codelineno-26-1"></a><?php </span><span id="__span-26-2"><a id="__codelineno-26-2" name="__codelineno-26-2" href="#__codelineno-26-2"></a> </span><span id="__span-26-3"><a id="__codelineno-26-3" name="__codelineno-26-3" href="#__codelineno-26-3"></a>use JsonException; </span><span id="__span-26-4"><a id="__codelineno-26-4" name="__codelineno-26-4" href="#__codelineno-26-4"></a> </span><span id="__span-26-5"><a id="__codelineno-26-5" name="__codelineno-26-5" href="#__codelineno-26-5"></a>try { </span><span id="__span-26-6"><a id="__codelineno-26-6" name="__codelineno-26-6" href="#__codelineno-26-6"></a> $json = json_encode("{", JSON_THROW_ON_ERROR); </span><span id="__span-26-7"><a id="__codelineno-26-7" name="__codelineno-26-7" href="#__codelineno-26-7"></a> return base64_encode($json); </span><span id="__span-26-8"><a id="__codelineno-26-8" name="__codelineno-26-8" href="#__codelineno-26-8"></a>} catch (JsonException $e) { </span><span id="__span-26-9"><a id="__codelineno-26-9" name="__codelineno-26-9" href="#__codelineno-26-9"></a> echo $e->getMessage(); // 类似json_last_error_msg() </span><span id="__span-26-10"><a id="__codelineno-26-10" name="__codelineno-26-10" href="#__codelineno-26-10"></a> echo $e->getCode(); // 类似 json_last_error() </span><span id="__span-26-11"><a id="__codelineno-26-11" name="__codelineno-26-11" href="#__codelineno-26-11"></a>} </span></code></pre></div> ### is_countable()验证变量是否可以计数类型 <div class="language-text highlight"><pre><span></span><code><span id="__span-27-1"><a id="__codelineno-27-1" name="__codelineno-27-1" href="#__codelineno-27-1"></a><?php </span><span id="__span-27-2"><a id="__codelineno-27-2" name="__codelineno-27-2" href="#__codelineno-27-2"></a> </span><span id="__span-27-3"><a id="__codelineno-27-3" name="__codelineno-27-3" href="#__codelineno-27-3"></a>// 7.3之前 </span><span id="__span-27-4"><a id="__codelineno-27-4" name="__codelineno-27-4" href="#__codelineno-27-4"></a>if (is_array($foo) || $foo instanceof Countable) { </span><span id="__span-27-5"><a id="__codelineno-27-5" name="__codelineno-27-5" href="#__codelineno-27-5"></a> // $foo is countable </span><span id="__span-27-6"><a id="__codelineno-27-6" name="__codelineno-27-6" href="#__codelineno-27-6"></a>} </span><span id="__span-27-7"><a id="__codelineno-27-7" name="__codelineno-27-7" href="#__codelineno-27-7"></a>// 7.3开始 </span><span id="__span-27-8"><a id="__codelineno-27-8" name="__codelineno-27-8" href="#__codelineno-27-8"></a>if (is_countable($foo)) { </span><span id="__span-27-9"><a id="__codelineno-27-9" name="__codelineno-27-9" href="#__codelineno-27-9"></a> // $foo is countable </span><span id="__span-27-10"><a id="__codelineno-27-10" name="__codelineno-27-10" href="#__codelineno-27-10"></a>} </span></code></pre></div> ### array_key_first(), array_key_last()获取数组第一个和最后一个key <div class="language-text highlight"><pre><span></span><code><span id="__span-28-1"><a id="__codelineno-28-1" name="__codelineno-28-1" href="#__codelineno-28-1"></a><?php </span><span id="__span-28-2"><a id="__codelineno-28-2" name="__codelineno-28-2" href="#__codelineno-28-2"></a> </span><span id="__span-28-3"><a id="__codelineno-28-3" name="__codelineno-28-3" href="#__codelineno-28-3"></a>$firstKey = array_key_first($array); </span><span id="__span-28-4"><a id="__codelineno-28-4" name="__codelineno-28-4" href="#__codelineno-28-4"></a>$lastKey = array_key_last($array); </span></code></pre></div> ### list支持引用赋值 <div class="language-text highlight"><pre><span></span><code><span id="__span-29-1"><a id="__codelineno-29-1" name="__codelineno-29-1" href="#__codelineno-29-1"></a><?php </span><span id="__span-29-2"><a id="__codelineno-29-2" name="__codelineno-29-2" href="#__codelineno-29-2"></a> </span><span id="__span-29-3"><a id="__codelineno-29-3" name="__codelineno-29-3" href="#__codelineno-29-3"></a>$array = [1, 2]; </span><span id="__span-29-4"><a id="__codelineno-29-4" name="__codelineno-29-4" href="#__codelineno-29-4"></a>list($a, &$b) = $array; </span></code></pre></div> 等效于: <div class="language-text highlight"><pre><span></span><code><span id="__span-30-1"><a id="__codelineno-30-1" name="__codelineno-30-1" href="#__codelineno-30-1"></a><?php </span><span id="__span-30-2"><a id="__codelineno-30-2" name="__codelineno-30-2" href="#__codelineno-30-2"></a> </span><span id="__span-30-3"><a id="__codelineno-30-3" name="__codelineno-30-3" href="#__codelineno-30-3"></a>$array = [1, 2]; </span><span id="__span-30-4"><a id="__codelineno-30-4" name="__codelineno-30-4" href="#__codelineno-30-4"></a>$a = $array[0]; </span><span id="__span-30-5"><a id="__codelineno-30-5" name="__codelineno-30-5" href="#__codelineno-30-5"></a>$b =& $array[1]; </span></code></pre></div> ## 参考 - [PHP 官方文档之各版本迁移](https://www.php.net/manual/zh/appendices.php) - [Evolution of PHP — v5.6 to v8.0](https://medium.com/@meskis/evolution-of-php-v5-6-to-v8-0-c3514ebb7f28) - [Usage statistics and market share of PHP for websites](https://w3techs.com/technologies/details/pl-php/all/all) - [The PHP Benchmark](https://phpbench.com/) - [How Fast is WordPress with PHP-FPM 7 Compare to 5?](https://geekflare.com/wordpress-php-fpm7/) 评论