本文要点
PHP 7.0 添加了空合并运算符(??),如果第一个操作数存在且其值不为 NULL,则返回第一个操作数,否则返回第二个操作数。PHP 7.4 还增加了对空合并赋值的支持。
PHP 7.0 添加了一个新的比较运算符(<=>)来比较表达式。
PHP 7.0 增加了对 Unicode codepoint 转义语法的支持,可以将十六进制格式转换为相应的 UTF-8 编码格式。
即使是从同一命名空间导入,use 语句也可以对类、函数和常量进行分组。
PHP 7.1 添加了一个短数组语法,可用于解包(unpacking)或析构(destructuring )数组。
PHP 7.1 增加了对类常量可见性的支持,这些常量可以声明为共有(public)、受保护(protected)和私有(private)。
PHP 7 支持在 try/catch 语句的同一 catch 块中指定多个异常。
在 PHP 7.0.0 中,关键字可用作标识符。
PHP 7.3 引入了灵活的 Heredoc 和 Nowdoc 语法,以提高可读性。
PHP 7.3 在数组和 list()析构中增加了对引用赋值的支持。
这是介绍 PHP 7.x 新特性系列文章的最后一篇,在本文中,我们将讨论其对数组、运算符、常量和异常处理的改进。
空合并运算符
isset
函数可用于确定一个变量是否被设置成非NULL
值。通常,isset
会与 PHP 的三元运算符结合使用,如下例所示。在这里,如果设置了GET
请求的参数 name ,isset
则返回 true,在这种情况下,变量的值被赋给变量$name
,否则$name
被设置成常量字符串值:
$name = isset($_GET['name']) ? $_GET['name'] : 'Deepak';
echo "Hello " . htmlspecialchars($name)."<br>";
复制代码
在 PHP 7.0 中已经添加了空合并运算符(null coalescing operator??
),它可用于简化此类操作。实际上,如果其第一个操作数存在且其值不为NULL
,它将返回第一个操作数,否则返回第二个操作数。前面的示例可以使用??
重写为:
$name = $_GET['name'] ?? 'Deepak';
复制代码
空合并运算符可以通过链式调用返回第一个定义了的值:
$name = $_GET['name'] ?? $_POST['name'] ?? 'Deepak';
echo "Hello " . htmlspecialchars($name)."<br>";
复制代码
现在,创建一个脚本 ternary.php,其中包括下面所有的示例:
<?php
$name = $_GET['name'] ?? 'Deepak';
echo "Hello " . htmlspecialchars($name)."<br>";
$name = isset($_GET['name']) ? $_GET['name'] : 'Deepak';
echo "Hello " . htmlspecialchars($name)."<br>";
$name = $_GET['name'] ?? $_POST['name'] ?? 'Deepak';
echo "Hello " . htmlspecialchars($name)."<br>";
?>
复制代码
如果不带请求参数运行脚本,那么所有示例都将输出最后指定的值:
Hello Deepak
Hello Deepak
Hello Deepak
复制代码
如果带有请求参数运行脚本,比如name=JohnSmith
,那么所有的示例都会输出在$_GET['name']
中接收到的请求参数:
Hello JohnSmith
Hello JohnSmith
Hello JohnSmith
复制代码
新的比较运算符
PHP 7.0 中添加了一个新的比较运算符(<=>),如果第一个表达式小于第二个表达式,则返回-1;如果两个表达式相同,则返回 0;如果第一个表达式大于第二个表达式,则返回 1。 PHP 的类型比较规则可用于执行比较。为了证明这一点,创建一个脚本 compare.php 来比较整数、浮点数和字符串的值:
<?php
// 整数
echo 1 <=> 1;
echo "<br>";
echo 1 <=> 0;
echo "<br>";
echo 5 <=> 10;
echo "<br>";
//浮点数
echo 1.0 <=> 1.5;
echo "<br>";
echo 1.0 <=> 1.0;
echo "<br>";
echo 0 <=> 1.0;
echo "<br>";
//字符串
echo "a" <=> "a";
echo "<br>";
echo "a" <=> "c";
echo "<br>";
echo "c" <=> "a";
echo "<br>";
?>
复制代码
如果运行脚本,将会得到如下的比较结果:
从十六进制格式到 UTF-8 的 Unicode codepoint 转换
PHP 7.0 添加了对 Unicode codepoint 转义语法的支持,该语法采用十六进制格式并返回相应的 UTF-8 编码格式。例如,在 Unicode 中,Ē
用U+0112
表示,其中前导 0 可以省略。要尝试 Unicode codepoint 转义语法,创建一个脚本 unicode.php。将如下代码复制到该脚本中:
<?php
echo "\u{0124}";
echo "\u{112}";
echo "\u{13B}";
echo "\u{13B}";
echo "\u{014C}";
?>
复制代码
如果运行脚本,将输出 UTF-8 字符串ĤĒĻĻŌ。
允许对“use”语句的别名命名空间进行分组
在 PHP 7.0 之前,从同一命名空间导入的每个类、函数和常量都必须使用单独的use
语句指定。在 PHP 7.0 中,即使是从同一个命名空间导入的类、函数和常量,也可以在同一个use
语句下分组。另外,从 PHP 7 开始,分组导入时允许使用尾随逗号。
举例来说,创建一个脚本 catalog.php 并声明一些属于同一命名空间的类、函数和常量,如下所示:
<?php
namespace Catalog;
class ClassA{
function hello(){
return "Hello from classA";
}
}
class ClassB{
function hello(){
return "Hello from classB";
}
}
class ClassC{
function hello(){
return "Hello from classC";
}
}
function fn_a(){
return "Message from fn_a()";
}
function fn_b(){
return "Message from fn_b()";
}
function fn_c(){
return "Message from fn_c()";
}
define("Catalog\ConstA", 1);
define("Catalog\ConstB", 2);
define("Catalog\ConstC", 3);
?>
复制代码
如你所见,虽然使用define()
声明的常量必须指定其全限定名,但对于用const
声明的常量,这一点并不适用。创建另一个脚本 group-namespace.php 并导入在 catalog.php 中定义的类、函数和常量。该脚本包含 catalog.php 的require
语句。类、函数和常量使用以下方式进行分组导入:
<?php
require('catalog.php');
use Catalog\{ClassA as A, ClassB as B, ClassC as C,};
use function Catalog\{fn_a, fn_b, fn_c,};
use const Catalog\{ConstA, ConstB, ConstC,Const1};
$a = new A();
echo $a->hello();
echo "<br/>";
$b = new B();
echo $b->hello();
echo "<br/>";
$c = new C();
echo $c->hello();
echo "<br/>";
echo fn_a();
echo "<br/>";
echo fn_b();
echo "<br/>";
echo fn_c();
echo "<br/>";
echo ConstA;
echo "<br/>";
echo ConstB;
echo "<br/>";
echo ConstC;
?>
复制代码
运行 group-namespace.php 脚本以访问分组导入的类、函数和常量并输出它们的值。
Hello from classA
Hello from classB
Hello from classC
Message from fn_a()
Message from fn_b()
Message from fn_c()
1
2
3
复制代码
用于析构数组赋值的短数组语法
前面我们提到过,PHP 7 中已经不再支持使用list()
解包(unpacking)字符串。无论如何,list()
仍继续支持对数组进行解包或析构以赋值给变量。在 PHP 7.1 中,添加了一种短数组语法来解包或析构数组。为了演示短数组语法的用法,创建一个脚本 array_syntax.php,并为不同的“杂志”(magazine)创建一个二维数组,并为每种“杂志”分配一个 id:
$catalog = [
[1, 'Oracle Magazine'],
[2, 'Java Magazine'],
[3, 'PHP Magazine'],
];
复制代码
要使用list()
将$catalog
数组析构或解包为$id
和$journal_name
,可以使用如下语法:
list($id1, $journal_name_1) = $catalog[0];
list($id2, $journal_name_2) = $catalog[1];
list($id3, $journal_name_3) = $catalog[2];
复制代码
另外,也可以使用新的数组析构语法,如下所示:
[$id1, $journal_name_1] = $catalog[0];
[$id2, $journal_name_2] = $catalog[1];
[$id3, $journal_name_3] = $catalog[2];
复制代码
list()
函数可以在foreach()
构造中使用,如下例所示:
foreach ($catalog as list($id, $journal_name)) {
echo "Journal $id is $journal_name";
echo "<br/>";
}
复制代码
与之等效的,使用数组语法[]
的foreach
如下所示:
foreach ($catalog as [$id, $journal_name]) {
echo "Journal $id is $journal_name";
echo "<br/>";
}
复制代码
下面列出了完整的 array_syntax.php 脚本:
<?php
$catalog = [
[1, 'Oracle Magazine'],
[2, 'Java Magazine'],
[3, 'PHP Magazine'],
];
echo "list() syntax";
echo "<br/>";
list($id1, $journal_name_1) = $catalog[0];
list($id2, $journal_name_2) = $catalog[1];
list($id3, $journal_name_3) = $catalog[2];
echo "Journal $id1 is $journal_name_1";
echo "<br/>";
echo "Journal $id2 is $journal_name_2";
echo "<br/>";
echo "Journal $id3 is $journal_name_3";
echo "<br/>";
echo "[] syntax";
echo "<br/>";
[$id1, $journal_name_1] = $catalog[0];
[$id2, $journal_name_2] = $catalog[1];
[$id3, $journal_name_3] = $catalog[2];
echo "Journal $id1 is $journal_name_1";
echo "<br/>";
echo "Journal $id2 is $journal_name_2";
echo "<br/>";
echo "Journal $id3 is $journal_name_3";
echo "<br/>";
echo "list() syntax";
echo "<br/>";
foreach ($catalog as list($id, $journal_name)) {
echo "Journal $id is $journal_name";
echo "<br/>";
}
echo "[] syntax";
echo "<br/>";
foreach ($catalog as [$id, $journal_name]) {
echo "Journal $id is $journal_name";
echo "<br/>";
}
?>
复制代码
如果运行脚本,你将看到新的短数组语法执行与list()
相同的数组拆包并输出相同的值,如下所示:
list() syntax
Journal 1 is Oracle Magazine
Journal 2 is Java Magazine
Journal 3 is PHP Magazine
[] syntax
Journal 1 is Oracle Magazine
Journal 2 is Java Magazine
Journal 3 is PHP Magazine
list() syntax
Journal 1 is Oracle Magazine
Journal 2 is Java Magazine
Journal 3 is PHP Magazine
[] syntax
Journal 1 is Oracle Magazine
Journal 2 is Java Magazine
Journal 3 is PHP Magazine
复制代码
与此相关,array_column
函数将返回输入数组的单个列的值。在以下语法中,该列由$column_key
标识
array array_column ( array $input , mixed $column_key [, mixed $index_key = NULL ] )
复制代码
PHP 7.0.0 添加了对输入参数作为对象数组的支持。为了演示这一点,创建一个脚本 array_column.php, 并声明一个带有两个字段$title
和$edition
的Catalog
类。创建两个Catalog
实例,并为它们设置值。然后创建一个包含两个Catalog
对象的对象数组:
$catalogs = array($Catalog1, $Catalog2);
复制代码
最后,使用array_column()
函数从对象数组中获取两个字段的值:
print_r(array_column($catalogs, 'title'));
print_r(array_column($catalogs, 'edition'));
复制代码
array_column.php 脚本如下所示:
<?php
class Catalog
{
public $title;
public $edition;
}
$Catalog1 = new Catalog();
$Catalog1->title = 'Oracle Magazine';
$Catalog1->edition = 'January-February2018';
$Catalog2 = new Catalog();
$Catalog2->title = 'Java Magazine';
$Catalog2->edition = 'March-April2018';
$catalogs = array($Catalog1, $Catalog2);
print_r(array_column($catalogs, 'title'));
print_r(array_column($catalogs, 'edition'));
?>
复制代码
如果运行这个脚本,它将会输出两个Catalog
对象的字段值:
Array ( [0] => Oracle Magazine [1] => Java Magazine ) Array ( [0] => January-February2018 [1] => March-April2018 )
复制代码
支持类常量可见性
PHP 7.1 增加了对类常量可见性的支持,这意味着可以将常量声明为公有(public)、受保护(protected)和私有(private)。只要声明公有常量的类是可访问的,公有常量就可以访问。受保护常量可以在同一类及其子类中访问。私有常量只能在同一类中访问。为了演示类常量可见性的用法,创建一个脚本 constants.php,并声明一个constants
类。在类中声明四个常量:一个没有访问修饰符,第二个带有public
访问修饰符,第三个带有protected
修饰符,第四个带有private
访问修饰符:
const A = 'A';
public const B = 2;
protected const C = 'C';
private const D = 4;
复制代码
类常量的默认可见性是public
。现在定义三个函数:带有公有访问修饰符的fn_a()
、带有私有访问修饰符的fn_b()
、带受保护访问修饰符的fn_c()
。每个函数都输出先前定义的四个常量的值:
echo constants::A;
echo constants::B;
echo constants::C;
echo constants::D;
复制代码
从 fn_a() 调用 fn_b() 。
$this->fn_b();
从 fn_b() 调用函数 fn_c() 。
$this->fn_c();
为了说明类中声明的所有常量都可以从同一个类中访问,而不管其所使用的可见性或访问修饰符如何,创建一个类常量实例并调用fn_a()
函数,该函数反过来调用fn_b()
,后者又调用fn_c()
:
$constants=new constants();
$constants->fn_a();
复制代码
为了说明私有常量在声明它们的同一个类中是可访问的,受保护常量只能从子类和同一个声明类中访问,声明一个类ClassA
,并在函数fn_a()
中输出每个常量的值:
class ClassA{
public function fn_a(){
echo constants::A;
echo constants::B;
echo constants::C;
echo constants::D;
}
复制代码
最后,为了说明公有和受保护的常量可以从子类中访问,而私有常量不能,声明constants
类的一个子类并在函数fn_d()
中输出每个常量的值:
class ClassB extends constants{
public function fn_d(){
echo constants::A;
echo constants::B;
echo constants::C;
echo constants::D;
}
复制代码
constants.php 脚本如下所示:
<?php
class constants
{
const A = 'A';
public const B = 2;
protected const C = 'C';
private const D = 4;
public function fn_a(){
echo constants::A;
echo "<br/>";
echo constants::B;
echo "<br/>";
echo constants::C;
echo "<br/>";
echo constants::D;
echo "<br/>";
$this->fn_b();
}
private function fn_b(){
echo constants::A;
echo "<br/>";
echo constants::B;
echo "<br/>";
echo constants::C;
echo "<br/>";
echo constants::D;
echo "<br/>";
$this->fn_c();
}
protected function fn_c(){
echo constants::A;
echo "<br/>";
echo constants::B;
echo "<br/>";
echo constants::C;
echo "<br/>";
echo constants::D;
echo "<br/>";
}
}
class ClassA{
public function fn_a(){
echo constants::A;
echo "<br/>";
echo constants::B;
echo "<br/>";
//echo constants::C; Uncaught Error: Cannot access protected const constants::C
echo "<br/>";
//echo constants::D;Uncaught Error: Cannot access private const constants::D
echo "<br/>";
}
}
class ClassB extends constants{
public function fn_d(){
echo constants::A;
echo "<br/>";
echo constants::B;
echo "<br/>";
echo constants::C;
echo "<br/>";
//echo constants::D;Uncaught Error: Cannot access private const constants::D
echo "<br/>";
}
}
$constants=new constants();
$constants->fn_a();
$classA=new ClassA();
$classA->fn_a();
$classB=new ClassB();
$classB->fn_d();
?>
复制代码
如果你尝试运行该脚本,如下所示的 echo 语句将生成这样的错误:Uncaught Error: Cannot access protected const constants::C.
class ClassA{
public function fn_a(){
…
echo constants::C;
…
}
..
}
复制代码
作为一个受保护的常量,constants::C
不能从任何非constants
派生的类中访问。现在,注释掉该语句并重新运行脚本。如下语句将导致脚本生成另一个错误Uncaught Error: Cannot access private const constants::D
:
class ClassA{
public function fn_a(){
…
echo constants::D;
…
}
…
}
复制代码
作为一个私有常量,constants::D
不能从任何其他类中访问。注释掉该语句,并再次运行脚本。脚本现在会生成另一个错误Uncaught Error: Cannot access private const constants::D
:
class ClassB extends constants{
public function fn_d(){
...
echo constants::D;
…
}
…}
复制代码
constants::D
是一个私有常量,不能从子类中访问它。注释掉该语句,并重新运行脚本。现在,可以得到如下输出:
每个 catch 块包含多个异常
现在,可以在try/catch
语句的同一个catch
块中指定多个异常,多个异常使用管道字符“|
”分隔。如果需要以相同的方式处理多个异常,那么该特性会非常有用。为了演示多异常 catch 块的用法,创建一个脚本 multi-catch-exception.php,并将如下代码复制到其中。该脚本声明了两个自定义的异常类和一个 try/catch 语句,该语句在另一个类(MultiCatch
)的test()
函数中,且该函数在 catch 块中声明了多个异常:
try {
throw new CustomException_2();
} catch (CustomException | CustomException_2 $e) {
var_dump(get_class($e));
}
复制代码
脚本 multi-catch-exception.php 如下所示:
<?php
class CustomException extends Exception { }
class CustomException_2 extends Exception { }
class MultiCatch {
public function test() {
try {
throw new CustomException_2();
} catch (CustomException | CustomException_2 $e) {
var_dump(get_class($e));
}
}
}
$multiCatch = new MultiCatch;
$multiCatch->test();
?>
复制代码
如果运行该脚本,在 try 块中抛出的异常将会在 catch 块中被捕获,如下所示:
string(17) "CustomException_2"
复制代码
改进了扩展加载语法
php.ini
中可用的扩展加载语法已经得到了改进。共享扩展不再需要.dll
(在 Windows 上)和.so
(在 Unix 上)后缀。例如,可以用如下方式指定 MySQL 数据库和 Oracle 数据库的扩展:
extension=mysqli
extension=oci8_12c
复制代码
关键字作为标识符
在 PHP 7.0.0 中,关键字可以用作类、接口和特征(trait)的属性、常量和方法名称。为了演示这一点,创建一个脚本 reserved_restriction.php,并将以下代码复制到该脚本中。该脚本使用保留关键字(int
、iterable
)来声明变量名。它还声明了一个常量null
(关键字)和一个true
(关键字)函数。
<?php
class Catalog {
public $int = 'hello ' . 'php';
public $iterable = '';
const null = 'null';
function true() {
}
}
$catalog=new Catalog();
$catalog->true();
?>
复制代码
如果运行该脚本,不会输出错误信息。使用关键字作为标识符可能的一个例外是,不能将常量命名为 class。为了演示这一点,在前面的脚本中添加以下代码:
如果运行该脚本,将生成以下错误信息:
A class constant must not be called 'class'; it is reserved for class name fetching.
灵活的 Heredoc 和 Nowdoc 语法
让我们先回顾一下Heredoc
和Nowdoc
语法。Heredoc
类似于双引号字符串,用开始和结束标记代替引号。使用 heredoc,在<<<
开始运算符之后,可以指定一个任意标识符,后跟一个换行符。随后是一个字符串,并且以相同的标识符结束引号。Nowdoc
与Heredoc
相似,不同之处在于开始标记放在单引号''
中,并且在Nowdoc
内不进行任何解析。
PHP 7.3 引入了灵活的Heredoc
和Nowdoc
语法,以提高可读性,并进行了如下的改进:
结束标记不需要后跟分号(”;“)。
结束标记不需要后跟换行符。
结束标记可以用制表符或空格缩进。制表符和空格不能混用。文档中的字符串文本可以缩进到与结束标记的缩进级别相同或更高。
结束标识符由与开始标识符相同的连续独立标记标识。
接下来,我们将用几个例子来演示下新的语法。但首先回顾一下旧语法:
print <<<EOT
Heredoc is similar to double-quoted string, with start and end markers replacing quotes.
EOT;
Heredoc 也可以赋值给变量:
<?php
class A {
public $a = <<<EOT
An example of heredoc as a variable value.
EOT;
}
?>
复制代码
下面是一个使用新语法的 Heredoc 示例。
<?php
$str = <<<EOD
The heredoc string
EOD;
echo <<<EOT
The heredoc string line 1
The heredoc string line 2
The heredoc string line 3
EOT
?>
复制代码
相反,下面的脚本并不是一个有效的 Heredoc 语法,会生成这样的错误:Parse error: Invalid indentation - tabs and spaces cannot be mixed.
<?php
{
echo <<<END
Heredoc text
END;
}
?>
复制代码
下面是Nowdoc
老语法的一个示例。
print <<<'EOT'
Nowdoc is similar to heredoc except that the start marker is enclosed in a single quote '' and no parsing is done inside a nowdoc.
EOT;
新 Nowdoc 语法的示例如下所示。
<?php
$str = <<<EOD
The heredoc string
EOD;
echo <<<'EOT'
The nowdoc string line 1
The nowdoc string line 2
The nowdoc string line 3
'EOT'
?>
复制代码
由于在 nowdoc 中不进行任何解析,因此下面示例的 nowdoc 字符串中包含冗余代码:
<?php
$str = <<<'EOD'
The heredoc text.
EOD;
class A
{
var $a;
var $b;
function __construct()
{
$this->a = 'A';
$this->b = array('B1', 'B2', 'B3');
}
}
$A = new A();
$c = 'C';
echo <<<'EOT'
Value of variable is "$c". Value of a variable from a class A is "$A->a".
Value of an array element from class A is "{$A->b[2]}".
Unicode for 'B' is U+0042
EOT
?>
复制代码
由于未执行任何解析,因此前面的脚本会生成如下的输出。
Value of variable is "$c". Value of a variable from a class A is "$A->a". Value of an array element from class A is "{$A->b[2]}". Unicode for 'B' is U+0042
如前所述,heredoc 和 nowdoc 主体缩进级别必须至少与结束标记的缩进级别相同。为了证明这一点,运行如下脚本。
<?php
echo <<<'EOT'
Line 1
Line 2
Line 3
EOT
?>
复制代码
在这种情况下,会产生以下错误:
Invalid body indentation level (expecting an indentation level of at least 5
支持数组析构中的引用赋值
PHP 7.3 增加了对数组和list()
析构中引用赋值的支持。首先让我们回顾一下什么是数组/列表(array/list)析构中的赋值。在下面的脚本中,将对数组进行析构,并将其元素值赋给一个列表:
<?php
list($a[], $a[], $a[]) = ['A', 2, 3];
var_dump($a);
?>
复制代码
var_dump
语句生成如下输出:
array(3) { [0]=> string(1) "A" [1]=> int(2) [2]=> int(3) }
现在,让我们来看一个新语法的示例:
list(&$a, [$b, &$c]) = $d
在本例中,列表元素$a
和$c
是通过引用赋值的。例如,创建以下脚本,其中$array[1]
元素通过引用$bvariable
赋值。这意味着,如果为$b
赋了一个新值,则新值也将赋给$array[1]
。
<?php
$array = ['A', 2];
list($a, &$b) = $array;
echo $a;
echo "<br/>";
echo $b;
echo "<br/>";
echo $array[1];
$b='b';
echo "<br/>";
echo $array[1];
复制代码
该脚本的输出如下:
如果不通过引用赋值而运行相同的脚本,则输出将不同。
list($a, $b) = $array;
使用上述赋值的输出如下:
最后,让我们考虑一个数组析构中引用赋值的示例。在下面的脚本中,数组元素通过引用变量b被赋值。如果b 的值被更改了,那么数组元素的值也会随之改变。
<?php
$array = [1, &$b];
$b='B';
echo $array[0];
echo "<br/>";
echo $array[1];
$b=2;
echo "<br/>";
echo $array[1];
复制代码
运行该脚本,将会得到如下的输出:
Instanceof 接受字面量
让我们首先回顾一下instanceof
运算符。在下面的脚本中,instanceof
用于确定对象是否为类 A 的实例:
<?php
class A{}
$obj = new A();
echo ($obj instanceof A);
?>
复制代码
如果运行该脚本,将输出 1。
PHP 7.3 添加了对将字面量用作第一个操作数的支持。在下面的脚本中,instanceof
的第一个操作数是一个字符串字面量:
<?php
class A{}
echo ('Hello PHP' instanceof A);
?>
复制代码
如果运行该脚本,将输出FALSE
。如果第一个操作数是一个字面量,instanceof
的输出总是FALSE
。
空合并赋值
我们前面讨论过在 PHP 7.0 中引入的空合并运算符??
。PHP 7.4 采用空合并运算符??
进一步添加了对空合并赋值的支持。比如,考虑以下情况。使用isset()
来确定是否设置了数组键,如果没有设置,则为其设置一个值
if (!isset($a['4'])) {
$a['4'] = setDefault();
}
复制代码
下面的脚本演示了如何对具有相同条件设置的数组键运用空合并赋值:
<?php
$a = array('1' => 'one', '2' => 'two', '3' => 'three');
$a['4'] ??= setDefault();
function setDefault()
{
return 'four';
}
var_dump($a);//array(4) { [1]=> string(3) "one" [2]=> string(3) "two" [3]=> string(5) "three" [4]=> string(4) "four" }
?>
复制代码
数字字面量分隔符
具有多个数字的数字字面量可能会由于长度的关系而变得无法识别,这可能会使调试变得相当困难。PHP 7.4 引入了下划线作为数字字面量的分隔符,以提高代码的可读性。下面的脚本在不同类型的变量中使用了数字分隔符“_”。
$_1=10_; // 用在末尾
$_2=1__2; // 用在下划线后
$_3=5_.0; 1._0; // 用在小数点后
$_4=0x_123; //用在x后
$_5=0b_111; //用在b后
复制代码
使用下划线作为数字字面量分隔符的唯一要求是它必须出现在两个数字之间。具体地说,它不能用在数字的末尾,也不能出现在另一个下划线或小数点旁边。变量名仍然可以以下划线开头。下面列举以错误方式将"_"用作数字字面量分隔符的所有示例:
$_1=10_; // 用在末尾
$_2=1__2; // 用在下划线旁
$_3=5_.0; 1._0; // 用在小数点后
$_4=0x_123; // 用在x后
$_5=0b_111; // 用在b后
$_6=2_e3; 2e_3; // 用在e旁
复制代码
在词法分析期间,数字字面量中的下划线将会被删除。
用于数组内解包的扩展运算符
在函数签名中,已经支持用由三个连续点(…)表示的扩展运算符对参数进行解包。PHP 7.4 增加了对扩展操作符的支持,以解包数组的元素。数组中支持的扩展运算符主要有如下特征:
实现Traversable
的数组和对象可以与扩展运算符一起使用。
扩展运算符可以在数组的任何位置使用,在元素之前或之后,甚至是连续使用都可以。
它可以与数组语法(array())和短语法([])一起使用。
函数返回的数组可以用 score 运算符解包。
数组不能通过引用解包。如果要解包的数组元素是通过引用存储的,那么解包之后,它们还将继续通过引用存储。
不支持字符串键。
下面的脚本演示了扩展操作符的使用。数组元素...$cd
使用了扩展操作符。...getArr()
对函数返回的数组进行解包。
<?php
$cd = ['c', 'd'];
$af = ['a', 'b', ...$cd,'e','f'];
var_dump($af);
function getArr() {
return ['c', 'd'];
}
$af = ['a', 'b',...getArr(), 'e','f'];
var_dump($af);
?>
复制代码
每个 var_dump 语句输出均为:
array(6) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" [3]=> string(1) "d" [4]=> string(1) "e" [5]=> string(1) "f" }
为了验证字符串键不能与扩展操作符一起使用,请运行如下脚本:
<?php
$cd = array("c" => "c","d" => "d");
$af = ['a', 'b', ...$cd,'e','f'];
var_dump($af);
复制代码
将会显示如下的错误信息:
Uncaught Error: Cannot unpack array with string keys
不再推荐使用花括号语法来访问数组元素
PHP 7.4 不推荐使用花括号来访问数组元素和字符串偏移量。无论如何,花括号语法只具有有限的功能。例如,它不能用于创建数组或将元素推入数组,也不能用于列表赋值。以下脚本仍可以使用,并能生成预期的输出字符串(1)“ a”。
<?php
$arr = ['a', 'b', 'c'];
var_dump($arr{0});
复制代码
但它也会显示一条警告信息:
Deprecated: Array and string offset access syntax with curly braces is deprecated
总结
在关于 PHP 7 系列的五篇文章中,我们已经按照特性类别分组的形式探讨了 PHP 7.x 中显著的新特性。在第一篇文章《PHP 7入门:OOP改进》中,我们设置了运行 PHP 7.x 脚本的环境,并介绍了与面向对象编程相关的改进。在第二篇文章《PHP 7 :类和接口的增强》中,我们介绍了对类和接口的改进。在第三篇文章《PHP 7:类型的新特性》中,我们介绍了 PHP 类型系统的改进。在第四篇《PHP 7:函数改进》中,我们介绍了与函数相关的改进。在本系列的最后一篇文章中,我们将介绍之前文章中没有涉及的改进,其中包括对数组、运算符、常量和异常处理的改进。
PHP 8.0 预计将于 2020 年 12 月初发布,并会提供一组新特性,但在此之前,仍需要学习使用 PHP 7.x。
作者介绍
Deepak Vohra 是一位 Sun 认证的 Java 程序员和 Sun 认证的 Web 组件开发人员。Deepak 在 WebLogic Developer’s Journal、XML Journal、ONJava、java.net、IBM developerWorks、Java Developer’s Journal、Oracle Magazine 和 devx 上都发表过 Java 和 Java EE 相关的技术文章。Deepak 还是一名 Docker 导师,已出版了五本关于 Docker 的书籍。Deepak 还发表了几篇关于 PHP 的文章,以及一本面向 PHP 和 Java 开发人员的 Ruby on Rails 书籍。
原文链接:
https://www.infoq.com/articles/php-7-array-operators/
相关阅读:
PHP 7 入门:新特性简介
PHP 7 入门:类和接口的增强
评论