写点什么

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

  • 2020-09-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-09-22 14:565711

评论

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

在前端领域摸爬滚打7年,我终于掌握了这些沉淀技巧

小鑫同学

国内AGV调度系统到底是什么水平?

申扬科技

调度系统 AGV

前端学习

阡陌r

经验分享:高德地图如何短时间快速完成春节出行备战工作?

阿里巴巴中间件

阿里云 云原生 函数计算

使用OpenAI接口释放ChatGPT API 的力量

devpoint

React nextjs ChatGPT

Kubernetes容器状态探测的艺术

俞凡

Kubernetes 云原生

大型供应链物流企业的数字化转型方法论

明道云

订单超时怎么处理?我们用这种方案

阿里巴巴中间件

阿里云 云原生

Spinner(列表选项框)的基本使用

芯动大师

android spinner galley

架构训练营-模块9秒杀系统

张Dave

如何设计一个优秀的 Go Web 项目目录结构

江湖十年

Go 设计 后端 项目 Web Service

工作一年,我重新理解了《重构》

阿里巴巴中间件

阿里云 云原生 重构

阿里云消息队列 Kafka 生态集成的实践与探索

阿里巴巴中间件

kafka 阿里云 云原生 消息队列

Matlab常用图像处理命令108例(二)

timerring

图像处理

28岁小公司程序员,无车无房不敢结婚,要不要转行?

程序员晚枫

程序员 收入

初识大热的ChatGPT的几点思考|社区征文

穿过生命散发芬芳

ChatGPT

【分布式技术专题】「分布式技术架构」一文带你厘清分布式事务协议及分布式一致性协议的算法原理和核心流程机制(上篇)

码界西柚

分布式 2PC 3PC 原理分析 分布式协议

从混乱到完备:我的研发流程之路

SkyFire

研发流程

AutoCompleteTextView的基本使用

芯动大师

android 控件 AutoCompleteTextView

LeSS敏捷框架高效生产力实践

俞凡

敏捷开发 大厂实践

JavaScript异步编程的深入理解,使用回调函数实现异步编程

兴科Sinco

JavaScript 前端 前端开发 异步编程

架构实战 8 - 消息队列MySql表格设计

架构实战营 「架构实战营」

强强联合:Neovim+ChatGPT | 社区征文

SkyFire

ChatGPT neovim

前端学习路径

阡陌r

Portraiture2023人像免费磨皮插件

茶色酒

Portraiture2023

将老人拉出无声的世界,AI是怎么做的?

脑极体

AI医疗

极氪汽车 APP 系统云原生架构转型实践

阿里巴巴中间件

阿里云 云原生

FL Studio21中文语言版水果编曲工具

茶色酒

FL Studio21

一天吃透Git面试八股文

程序员大彬

git 面试

统一观测丨使用 Prometheus 监控 E-MapReduce,我们该关注哪些指标?

阿里巴巴中间件

阿里云 云原生

巧用GenericObjectPool创建自定义对象池

京东科技开发者

京东云 API 编排 对象池 京东物流 企业号 3 月 PK 榜

PHP 7 入门:数组、运算符、常量及异常处理的改进_语言 & 开发_Deepak Vohra_InfoQ精选文章