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 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>";
?>

如果運行腳本,將會得到如下的比較結果:

0
1
-1
-1
0
-1
0
-1
1

從十六進制格式到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.phprequire語句。類、函數和常量使用以下方式進行分組導入:

<?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$editionCatalog類。創建兩個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是一個私有常量,不能從子類中訪問它。註釋掉該語句,並重新運行腳本。現在,可以得到如下輸出:

A
2
C
4
A
2
C
4
A
2
C
4
A
2




A
2
C

每個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,並將以下代碼複製到該腳本中。該腳本使用保留關鍵字(intiterable)來聲明變量名。它還聲明瞭一個常量null(關鍵字)和一個true(關鍵字)函數。

<?php
class 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也可以賦值給變量:

<?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];

該腳本的輸出如下:

A
2
2
b

如果不通過引用賦值而運行相同的腳本,則輸出將不同。

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

使用上述賦值的輸出如下:

A
2
2
2

最後,讓我們考慮一個數組析構中引用賦值的示例。在下面的腳本中,數組元素通過引用變量$b被賦值。如果$b的值被更改了,那麼數組元素的值也會隨之改變。

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

運行該腳本,將會得到如下的輸出:

1
B
2

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 入門:類和接口的增強

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章