PHP 7入門:新特性簡介

本文要點

  • PHP 7是人們期待已久的、PHP 5的後繼版本。 PHP 7.4是PHP 7的最後一個小版本。
  • 除提供了多項新特性外,PHP 7.x速度更快,而且已經雲就緒。
  • PHP 7.2部分支持協變和逆變,PHP 7.4實現了完全支持。
  • PHP 7.2新增了類型object
  • PHP仍然是Web上最常見的語言之一。在服務端編程語言已知的網站中,78.6%的使用了PHP

PHP快成爲一種被遺忘的語言了,自2004年PHP 5.0發佈之後,十多年沒有一個新的大版本。更糟糕的是,PHP 6.x被放棄是因爲計劃向PHP添加原生Unicode支持卻無法實現。

PHP 7.0是一個大版本,增加了一些改進和新特性。7.0中有一些比較顯著的新特性,包括:字符串、整數、浮點數和布爾值的標量類型聲明;返回類型聲明;用於數組常量的新函數define() ;匿名類。該版本還添加了一些特性來改進Unicode支持,包括IntlChar類和Unicode代碼點轉義語法。

此外,PHP 7還添加了增強assert()函數的期望(expectations ),而生成器返回函數和生成器委託改進了生成器的功能。隨後的小版本,從PHP 7.1到PHP 7.4,還增加了其他新特性。

在本系列文章中,我們將討論PHP 7.x版本中的各種新特性。但首先,讓我們探討一下爲什麼使用PHP 7。

爲什麼使用PHP 7?

簡單來說,PHP 7讓PHP達到了其他現代語言的水平。

下面是使用PHP 7其中一些最重要的原因:

  1. 在所有的網站中,有36.4%使用WordPress。PHP 7是WordPress官方推薦的PHP版本。

當更新PHP的版本時,WordPress建議更新到推薦的PHP 7.3版本。PHP內部團隊做得很棒,他們讓最新版本成爲PHP迄今爲止最快的版本。這意味着更新將提高你網站的速度,對你和你的訪問者而言都是如此。

  1. PHP 7提供了前面提到的多項新特性。

  2. PHP 7基於一個新引擎Zend Engine,性能更好,速度更快。Zend非常快,這一點從幾個在不同平臺/配置下運行的速度基準測試中可以看出來。

  3. PHP 7使用了高效的數據結構,使其比之前的版本更簡潔。

  4. PHP 7已經雲就緒,大部分主流雲服務提供商的LAMP Stack都支持它。

環境設置

要測試或運行本文提供的示例腳本,請下載並安裝PHP 7的最新版本(PHP 7.4)。平臺不同,下載的二進制文件和安裝步驟也會有些差異,因此,請參閱官方PHP文檔。不要忘記將安裝根目錄,例如C:\PHP7.4\php-7.4-ts-windows-vc15-x64-r6c9821a添加到PATH 環境變量中。將php.ini-productionphp.ini-development重命名爲php.ini。要使用/ext目錄中的擴展,請在php.ini中設置extension_dir指令:

extension_dir = "./ext"

使用下面的命令啓動內置服務器:

php -S localhost:8000

在根目錄(即安裝目錄,例如,C:\PHP7\php-7.3.0-Win32-VC15-x64)的scripts子目錄中添加要運行的所有腳本。可以使用php.ini中的doc_root指令將根目錄設置爲不同的路徑。要重用本示例中的PHP腳本,請單獨保存它們,而不是將每個腳本作爲test.php測試/運行。

協變和逆變

PHP 7.2引入了有限協變和逆變。協變是指子類的方法能夠返回更具體的返回類型。逆變是指子類的方法接受不那麼具體的參數類型。更具體/不那麼具體是在超/子類的上下文中定義的,子類是更具體的。一個類擴展另一個類可以重寫其方法,同時仍然保持逆變(對於參數類型)和協變(對於返回類型)。

PHP 7.2僅提供對協變和逆變的有限支持,這意味着只支持沒有提供類型的情況。具體來說,可以在重寫超類中不存在返回類型的函數時定義返回類型,而在重寫超類中存在參數的函數時省略參數類型。

例如,創建一個腳本,聲明一個只有一個函數fn1的類A,創建另一個類B,繼承類A並重寫其fn1 函數。

在重寫後的函數fn1中,參數類型被刪除了,默認成了mixed類型,該參數類型比類A中的類型B更寬泛。在重寫後的方法中刪除參數類型,而不管類是否是抽象的,這是PHP 7的另一項新特性。

重寫後的fn1方法返回類型是A,其範圍要比類A中的mixed類型窄。以下是代碼:

<?php
class A {
  function fn1(B $b) {} 
}
class B extends A {
  function fn1($b): A{} 
}

新對象類型

PHP 7.2新增了一個類型object,該類型可以用作參數類型和返回類型。所有類類型的實例都是對象。爲了演示如何使用object作爲參數類型和返回類型,在文檔根目錄下的scripts目錄中創建一個腳本object.php,並聲明兩個類ClassAClassB,每個類都定義 一個hello()函數,該函數回顯字符串消息。接下來,向腳本本身添加hello()函數,參數類型和返回類型都是object。直接在腳本中添加的hello()函數返回類ClassB的一個實例:

function hello(object $obj) : object
{
	return new ClassB();
}

使用ClassA類的實例作爲參數調用該函數,並在返回的對象上調用hello()函數。

hello(new ClassA())->hello();
The object.php is listed:
<?php
Class ClassA{
function hello()
{
	echo "Hello from ClassA";
}}
class ClassB{
function hello()
{
 	echo "Hello from ClassB";
}}
 
function hello(object $obj) : object
{
	return new ClassB();
}
hello(new ClassA())->hello();
?>

使用URL http://localhost:8000/scripts/object.php運行腳本,輸出如下:
Hello from ClassB

由於這是我們運行的第一個示例腳本,所以我們把它在瀏覽器中的輸出截了圖,如下所示:

圖1:object.php的輸出

object類型本身並不代表一個類;它只是一個類型。如果object之外的任何類型轉化爲objec,就會創建內置類stdClass的一個實例。

數組可以強制轉換爲對象類型object,生成的對象具有名稱類似數組鍵的屬性。爲了演示如何將數組轉換爲對象以及幾項有用的相關任務,請創建object_array.php腳本並通過強制轉換爲object來聲明對象。

$obj = (object) array('journal' => 'Oracle Magazine', 'publisher' => 'Oracle Publishing','edition' => 'January February 2018');

現在,可以使用命名鍵來輸出對象屬性了。

echo $obj->{'journal'};
echo $obj->{'publisher'};
echo $obj->{'edition'};

bool isset (mixed$var [,mixed$... ])函數可以用於檢查屬性是否已經像下面這樣設置:
var_dump(isset($obj->{'journal'}));

使用mixedkey ( array $array)函數輸出一個對象鍵。

var_dump(key($obj));

使用mixed next ( array &$array)前移內部數組指針。

next($obj);

調用issetkey函數獲取下一個數組元素。按順序重複調用nextissetkey函數獲取下一個元素。可以直接訪問對象成員變量來輸出它們的值。

echo $obj->journal; 
echo $obj->publisher;
echo $obj->edition; 

檢查從數組轉換而來的對象是否是stdClass的實例。

if($obj instanceof stdClass){
echo '$obj is instance of built-in class stdClass';
}

字符串可以強制轉換爲object。轉換後的對象的值可以使用成員變量scalar訪問。檢查轉換後的對象是否爲stdClass的實例。

$obj = (object) 'hello';
echo $obj->scalar;
if($obj instanceof stdClass){
echo '$obj is instance of built-in class stdClass';
}

以下是object_array.php腳本的內容:

<?php
$obj = (object) array('journal' => 'Oracle Magazine', 'publisher' => 'Oracle Publishing','edition' => 'January February 2018');
echo $obj->{'journal'};
echo "<br/>";
echo $obj->{'publisher'};
echo "<br/>";
echo $obj->{'edition'};
echo "<br/>";
var_dump(isset($obj->{'journal'})); 
echo "<br/>";
var_dump(key($obj));
next($obj);
echo "<br/>";
var_dump(isset($obj->{'publisher'})); 
echo "<br/>";
var_dump(key($obj));
next($obj);
echo "<br/>";
var_dump(isset($obj->{'edition'})); 
echo "<br/>";
var_dump(key($obj));
echo "<br/>";
echo $obj->journal; 
echo "<br/>";
echo $obj->publisher;
echo "<br/>";
echo $obj->edition; 
echo "<br/>";
if($obj instanceof stdClass){
echo '$obj is instance of built-in class stdClass';
echo "<br/>";
}
$obj = (object) 'hello';
echo $obj->scalar;
echo "<br/>";
if($obj instanceof stdClass){
echo '$obj is instance of built-in class stdClass';
}
?>

運行該腳本會輸出以下內容:

Oracle Magazine
Oracle Publishing
January February 2018
bool(true)
string(7) "journal"
bool(true)
string(9) "publisher"
bool(true)
string(7) "edition"
Oracle Magazine
Oracle Publishing
January February 2018
$obj is instance of built-in class stdClass
hello
$obj is instance of built-in class stdClass

不僅可以將數組和字符串轉換爲對象,還可以將任何類型的值轉換爲對象,包括intfloatbool。例如,將int轉換爲object,輸出其scalar值,然後用接下來的腳本檢查轉換後的對象是否爲stdClass的實例:

<?php
$obj = (object) 1;
echo $obj->scalar;
echo "<br/>";
if($obj instanceof stdClass){
echo '$obj is instance of built-in class StdClass';
}?>

輸出如下:
1

$obj is instance of built-in class stdClass

類的實例是對象而不是stdClass的實例,將它們轉換爲object不會使它們成爲stdClass的實例。爲了演示這一點,我們創建一個名爲object_instance_of.php的腳本。然後聲明一個類並實例化它。下面的腳本將展示如何確定一個類的實例是否是stdClass的實例;接下來,該腳本會將類的實例強制轉換爲object,並確定轉換後的對象是否是stdClass的實例。object_instance_of.php腳本如下所示:

<?php
Class A{}
$A = new A;
echo '<br/>';
if ($A instanceof stdClass) {
echo '$A is instance of built-in class stdClass'; }
else{
echo '$A is not instance of built-in class stdClass';
}
echo '<br/>';
echo '<br/>';
$AObj = (object)$A;
 if ($AObj instanceof stdClass) {
 echo   '$AObj is instance of built-in class stdClass';
}else{ echo   '$AObj is not instance of built-in class stdClass';
}
echo '<br/>';
 ?>

以下是該腳本的輸出:

$A is not instance of built-in class stdClass
$AObj is not instance of built-in class stdClass

命名類或匿名類的實例已經是object,將其強制轉換爲object不會改變其類型。空數組和NULL值也可以轉換爲object。如前所述,stdClass是默認的PHP對象,當將標量、數組和NULL強制轉換爲object時,將創建stdClass的一個實例。匿名類object、從空數組創建的object、從NULL創建的object或沒有函數或變量的類都不會被認爲是空的,將empty()應用於它們中的任何一個都不會返回TRUEempty()函數的作用是:僅當變量或對象不存在或它的值爲FALSE時才返回TRUE
如果你想測試一下,可以創建一個腳本文件object_empty.php,並將下面的代碼粘貼進去:

<?php
$obj1 = (object)(new class{}); // 實例化匿名類
$obj2 = (object)[]; // 將空數組轉換爲對象
class A{}
$A=new A();  // 空類的實例
var_dump($A);
echo "<br/>";
var_dump($obj1);
echo "<br/>";
var_dump($obj2);
echo "<br/>"; 
echo empty ($obj1);
echo "<br/>";
$obj1=NULL;
$obj3=(object)$obj1;// NULL轉換爲對象
var_dump($obj3); 
echo "<br/>";
echo empty ($A);
echo "<br/>";
echo empty ($obj2);
echo "<br/>";
echo empty ($obj3);
?>

該腳本創建了每一種匿名類的對象:從空數組創建的對象,從NULL創建的對象,以及沒有函數或變量的類對象。運行該腳本將生成以下輸出。

object(A)#3 (0) { } 
object(class@anonymous)#1 (0) { } 
object(stdClass)#2 (0) { };
object(stdClass)#1 (0) { } 

object類型可以用於參數類型的逆變(放寬)和返回類型的協變(縮窄)。

<?php
class A{
public function fn(object $obj)  {
}
}
class B extends A{
public function fn($obj) : object {
} 
} 

完全協變和逆變

我們已經討論了PHP 7.2對有限協變的支持,它支持向擴展類中的方法添加返回類型,即使在超類中沒有聲明任何返回類型。我們還討論了對有限逆變的支持,它允許在擴展類中不指定方法參數的類型。

PHP 7.4添加了對協變和逆變的完全支持。完全支持允許開發人員使用不那具體的參數類型和更具體的返回類型,這意味着參數類型可以用它的超類型替換,而返回類型可以用子類型替換。回想一下,PHP 7.2中對協變和逆變的支持僅限於無類型。在下面的腳本中,ClassB繼承了ClassAClassD繼承了ClassC。與ClassC相比,ClassD中的函數fn1聲明瞭一個不那麼具體的參數類型和一個更具體的返回類型。

<?php
class ClassA {}
class ClassB extends ClassA {}
class ClassC {
    public function fn1(ClassB $b): ClassA {}
}
class ClassD extends ClassC {
    public function fn1(ClassA $a): ClassB {}
}
?>

以下是全變型支持的部分特性:

  • 只有在使用自動加載時,才能提供全變型支持;
  • 支持object類型變型;
  • 不支持callable類型變型;
  • 引用參數仍然是逆變的,引用返回類型仍然是協變的;
  • 變型驗證是在最後一個連續類型(consecutive type)聲明後才進行。

在本系列的下一篇文章中,我們將討論PHP 7.x中類和接口的新特性。

作者簡介:

Deepak Vohra是Sun認證Java程序員和Web組件開發人員。他一直在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的文章,並出版了一本著作Ruby on Rails for PHP and Java Developers

原文鏈接:

PHP 7 — Getting Started and OOP Improvements

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