GMTC深圳站本周日开幕,14大专题全部上线,完整日程>> 了解详情
写点什么

PHP 7 入门:数组、运算符、常量及异常处理的改进

  • 2020 年 9 月 22 日
  • 本文字数:11211 字

    阅读完需:约 37 分钟

PHP 7 入门:数组、运算符、常量及异常处理的改进

本文要点


  • 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 DeepakHello DeepakHello Deepak
复制代码


如果带有请求参数运行脚本,比如name=JohnSmith,那么所有的示例都会输出在$_GET['name']中接收到的请求参数:


Hello JohnSmithHello JohnSmithHello 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>";?>
复制代码


如果运行脚本,将会得到如下的比较结果:


01-1-10-10-11
复制代码


从十六进制格式到 UTF-8 的 Unicode codepoint 转换

PHP 7.0 添加了对 Unicode codepoint 转义语法的支持,该语法采用十六进制格式并返回相应的 UTF-8 编码格式。例如,在 Unicode 中,ĒU+0112表示,其中前导 0 可以省略。要尝试 Unicode codepoint 转义语法,创建一个脚本 unicode.php。将如下代码复制到该脚本中:


<?phpecho "\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 并声明一些属于同一命名空间的类、函数和常量,如下所示:


<?phpnamespace 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语句。类、函数和常量使用以下方式进行分组导入:


<?phprequire('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 classAHello from classBHello from classCMessage from fn_a()Message from fn_b()Message from fn_c()123
复制代码


用于析构数组赋值的短数组语法

前面我们提到过,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() syntaxJournal 1 is Oracle MagazineJournal 2 is Java MagazineJournal 3 is PHP Magazine[] syntaxJournal 1 is Oracle MagazineJournal 2 is Java MagazineJournal 3 is PHP Magazinelist() syntaxJournal 1 is Oracle MagazineJournal 2 is Java MagazineJournal 3 is PHP Magazine[] syntaxJournal 1 is Oracle MagazineJournal 2 is Java MagazineJournal 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$editionCatalog类。创建两个Catalog实例,并为它们设置值。然后创建一个包含两个Catalog对象的对象数组:


$catalogs = array($Catalog1, $Catalog2);
复制代码


最后,使用array_column()函数从对象数组中获取两个字段的值:


print_r(array_column($catalogs, 'title'));print_r(array_column($catalogs, 'edition'));
复制代码


array_column.php 脚本如下所示:


<?phpclass 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 脚本如下所示:


<?phpclass 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::Decho "<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::Decho "<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是一个私有常量,不能从子类中访问它。注释掉该语句,并重新运行脚本。现在,可以得到如下输出:


A2C4A2C4A2C4A2



A2C
复制代码


每个 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 如下所示:


<?phpclass 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=mysqliextension=oci8_12c
复制代码


关键字作为标识符

在 PHP 7.0.0 中,关键字可以用作类、接口和特征(trait)的属性、常量和方法名称。为了演示这一点,创建一个脚本 reserved_restriction.php,并将以下代码复制到该脚本中。该脚本使用保留关键字(intiterable)来声明变量名。它还声明了一个常量null(关键字)和一个true(关键字)函数。


<?phpclass Catalog {  public $int = 'hello ' . 'php';  public $iterable = '';  const null = 'null';  function true() {  }}$catalog=new Catalog(); $catalog->true();?>
复制代码


如果运行该脚本,不会输出错误信息。使用关键字作为标识符可能的一个例外是,不能将常量命名为 class。为了演示这一点,在前面的脚本中添加以下代码:


const class=1;
复制代码


如果运行该脚本,将生成以下错误信息:


A class constant must not be called 'class'; it is reserved for class name fetching.


灵活的 Heredoc 和 Nowdoc 语法

让我们先回顾一下HeredocNowdoc语法。Heredoc类似于双引号字符串,用开始和结束标记代替引号。使用 heredoc,在<<<开始运算符之后,可以指定一个任意标识符,后跟一个换行符。随后是一个字符串,并且以相同的标识符结束引号。NowdocHeredoc相似,不同之处在于开始标记放在单引号''中,并且在Nowdoc内不进行任何解析。


PHP 7.3 引入了灵活的HeredocNowdoc语法,以提高可读性,并进行了如下的改进:


  1. 结束标记不需要后跟分号(”;“)。

  2. 结束标记不需要后跟换行符。

  3. 结束标记可以用制表符或空格缩进。制表符和空格不能混用。文档中的字符串文本可以缩进到与结束标记的缩进级别相同或更高。

  4. 结束标识符由与开始标识符相同的连续独立标记标识。


接下来,我们将用几个例子来演示下新的语法。但首先回顾一下旧语法:


print <<<EOT


Heredoc is similar to double-quoted string, with start and end markers replacing quotes.


EOT;


Heredoc 也可以赋值给变量:


<?phpclass A {  public $a = <<<EOTAn 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 主体缩进级别必须至少与结束标记的缩进级别相同。为了证明这一点,运行如下脚本。


<?phpecho <<<'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)析构中的赋值。在下面的脚本中,将对数组进行析构,并将其元素值赋给一个列表:


<?phplist($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];
复制代码


该脚本的输出如下:


A22b
复制代码


如果不通过引用赋值而运行相同的脚本,则输出将不同。


list($a, $b) = $array;


使用上述赋值的输出如下:


A222
复制代码


最后,让我们考虑一个数组析构中引用赋值的示例。在下面的脚本中,数组元素通过引用变量b 的值被更改了,那么数组元素的值也会随之改变。


<?php$array = [1, &$b]; $b='B';echo $array[0];echo "<br/>";echo $array[1];$b=2;echo "<br/>";echo $array[1];
复制代码


运行该脚本,将会得到如下的输出:


1B2
复制代码


Instanceof 接受字面量

让我们首先回顾一下instanceof运算符。在下面的脚本中,instanceof用于确定对象是否为类 A 的实例:


<?phpclass A{}$obj = new A();echo ($obj instanceof A);?>
复制代码


如果运行该脚本,将输出 1。


PHP 7.3 添加了对将字面量用作第一个操作数的支持。在下面的脚本中,instanceof的第一个操作数是一个字符串字面量:


<?phpclass 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 入门:类和接口的增强


2020 年 9 月 22 日 14:561732

评论

发布
暂无评论
发现更多内容

云原生应用Go语言:你还在考虑的时候,别人已经应用实践

华为云开发者社区

微服务 云技术 Go 语言

什么是堡垒机?为什么需要堡垒机?

xcbeyond

运维

大厂都是怎么用Java8代替SimpleDateFormat?

Java架构师迁哥

Web前端如何实现断点续传

QiLab

Web 断点续传 upload pl

LeetCode题解:169. 多数元素,分治,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

双指针算法和位运算&离散化和区间合并

落曦

原创 | 使用JPA实现DDD持久化-只要O,忘记R & Maven配置

编程道与术

Java hibernate 编程 mybatis jpa

我是面试官,我来分享一波面经!看看我的内心OS

比伯

Java 编程 架构 面试 技术宅

视频作品播放量低:自媒体作者如何走出新手村

石头IT视角

英特尔与南京溧水经济技术开发区共同成立智能交通研究院

新闻科技资讯

打工人、打工魂、高效MES助力打工者都是人上人

Marilyn

敏捷开发 快速开发 MES系统

性能测试界“网红”云性能测试服务,了解一下?

华为云开发者社区

CloudTest 沙箱实验 云性能测试

About Me

翎君

android

有奖话题 | 如果程序员和产品经理都会凡尔赛文学,将如何对话?

YourBatman

话题讨论 凡尔赛文学

容器化时代到来!跳转机分配问题终于“有救”了

华为云开发者社区

容器 镜像 网络

原创 | TDD工具集:JUnit、AssertJ和Mockito (二十七)运行测试-在构建工具中运行测试

编程道与术

Java 编程 TDD 单元测试 JUnit

【JAVA】List转换为array

莫问

在线K歌的发展和优势

anyRTC开发者

音视频 WebRTC RTC sdk

如何基于App SDK快速地开发一个IoT App?

IoT云工坊

App 物联网 sdk 智能家居

申通快递 双11 云原生应用实践

阿里巴巴云原生

阿里云 Kubernetes 运维 云原生 监控

如何用CSS实现图像替换链接文本显示并保证链接可点击

陈北

CSS小技巧

程序员面试的时候突然遇到答不上的问题怎么办?

Java架构师迁哥

架构师训练营 1 期 -- 第十周总结

曾彪彪

极客大学架构师训练营

大厂经验:埋点数据质量之埋点验证

阿亮

埋点 数据验证

30分钟开发一款抓取网站图片资源的浏览器插件

徐小夕

Java chrome 前端 chrome扩展

马士兵最新2020涵盖P5—P8Java全栈架构师学习路线,跟着老师学我已拿P7Offer!

Java架构追梦

Java 学习 架构 面试 马士兵

基于DAYU的实时作业开发,分分钟搭建企业个性化推荐平台

华为云开发者社区

华为 算法 数据 dayu

纷享销客罗旭:拐点下的中国SaaS

ToB行业头条

SaaS

《迅雷链精品课》第七课:以太坊数据存储分析

迅雷链

区块链

moon不讲武德!!!一个类加载机制给面试官说蒙了!!

moon聊技术

Java JVM 类加载 类加载器

接口请求(get、post、head等)详解

测试人生路

HTTP

2021星空论坛:破局创新,论道数字化转型

2021星空论坛:破局创新,论道数字化转型

PHP 7 入门:数组、运算符、常量及异常处理的改进-InfoQ