前沿拓展:
運(yùn)行啟動項
一、聲卡控制面板設(shè)置(部分聲卡都會有這方便的問題,如:Realtek、via) 打開音頻管理器——點(diǎn)擊右側(cè)接點(diǎn)擊安裝。
作者 | Deepak Vohra
譯者 | 劉雅夢
策劃 | 丁曉昀
本文屬于專題文章《深入淺出 PHP 8》。 根據(jù)w3tech的數(shù)據(jù),PHP 仍然是 Web 上使用最廣泛的腳本語言之一,77.3%的網(wǎng)站使用 PHP 進(jìn)行服務(wù)器端編程。PHP 8 帶來了許多新特性和其他改進(jìn),我們將在本系列文章中進(jìn)行探討。PHP 8.0 添加了對多個函數(shù)和方法相關(guān)特性的支持,其中一些是對現(xiàn)有特性的改進(jìn),而另一些則是全新的特性。PHP 8.1 中增強(qiáng)的可調(diào)用語法可用于通過可調(diào)用對象創(chuàng)建匿名函數(shù)。命名函數(shù)參數(shù)可以與位置參數(shù)一起使用,另外還有一個好處,即命名參數(shù)沒有順序,可以通過它們的名稱來傳達(dá)含義。纖程(Fiber)是可中斷的函數(shù),增加了對多任務(wù)的支持。
重新定義了私有方法上的繼承
對象繼承是大多數(shù)面向?qū)ο笳Z言(包括 PHP)所使用的編程范式。它可以從任何擴(kuò)展類中重寫公共和受保護(hù)的方法,以及在類中定義的類屬性和常量。在 PHP 中,公共方法不能通過更嚴(yán)格的訪問來重新實(shí)現(xiàn),例如將 public 方法設(shè)為 private 。為了演示這一點(diǎn),考慮一個擴(kuò)展了類 A 的類 B,它重新實(shí)現(xiàn)了類 A 中一個公共方法。
<?php
class A{
public function sortArray():string{
return "Class A method";
}
}
class B extends A{
private function sortArray():string{
return "Class B method";
}
}
$b=new B();
echo $b->sortArray();
運(yùn)行時,腳本會生成如下的一條錯誤信息:
致命錯誤:B::sortArray()的訪問級別必須是公共的(與類A一樣)
公共方法不能重新實(shí)現(xiàn)。
相反,在類中定義的私有方法不是繼承的,可以在擴(kuò)展它的類中重新實(shí)現(xiàn)。例如,類 B 在下面的腳本中擴(kuò)展了類 A,并重新實(shí)現(xiàn)了類 A 中一個私有方法。
<?php
class A{
private function sortArray():string{
return "Class A method";
}
}
class B extends A{
private function sortArray(int $a):string{
return "Class B method";
}
}
在 PHP 8.0 之前,對擴(kuò)展類中私有方法的重新聲明應(yīng)用了兩個限制:不允許更改 final 和 static 修飾符。如果 private 方法被聲明為 final ,則不允許擴(kuò)展類重新聲明該方法。如果私有方法被聲明為靜態(tài)的,那么它將在擴(kuò)展類中保持靜態(tài)。而且,如果私有方法沒有static 修飾符,則不允許擴(kuò)展類添加static 修飾符。在 PHP 8 中,這兩個限制都被取消了。以下腳本在 PHP 8 中能正常運(yùn)行。
<?php
class A {
private final static function sortArray():string{
return "Class A method";
}
}
class B extends A {
private function sortArray(int $a):string{
return "Class B method";
}
}
PHP 8 中唯一的私有方法限制是強(qiáng)制使用 private final 構(gòu)造函數(shù),當(dāng)使用靜態(tài)工廠方法作為替代時,有時會使用private final來禁用構(gòu)造函數(shù)。
<?php
class A {
private final function __construct(){
}
}
class B extends A {
private final function __construct(){
}
}
該腳本生成如下的錯誤信息:
致命錯誤:不能重寫最終方法A::__construct()
可變參數(shù)可以替換任意數(shù)量的函數(shù)參數(shù)
在 PHP 8 中,單個可變參數(shù)可以替換任意數(shù)量的函數(shù)參數(shù)??紤]下面的腳本,其中類 B 擴(kuò)展了類 A,并用一個可變參數(shù)替換函數(shù) sortArray 的三個參數(shù)。
<?php
class A {
public function sortArray(array $arrayToSort, string $sortType, int $arraySize) {
if ($sortType == "asc") {
sort($arrayToSort);
foreach ($arrayToSort as $key => $val) {
echo "$key = $val ";
}
} elseif ($sortType == "desc") {
rsort($arrayToSort);
foreach ($arrayToSort as $key => $val) {
echo "$key = $val ";
}
}
}
}
class B extends A {
public function sortArray(…$multiple) {
$arrayToSort= $multiple[0];
$sortType=$multiple[1];
if ($sortType == "asc") {
sort($arrayToSort);
foreach ($arrayToSort as $key => $val) {
echo "$key = $val ";
}
} elseif ($sortType == "desc") {
rsort($arrayToSort);
foreach ($arrayToSort as $key => $val) {
echo "$key = $val ";
}
}
}
}
可以使用多個參數(shù)調(diào)用類 B 中的 sortArray 函數(shù)。
$sortType="asc";
$arrayToSort=array("B", "A", "f", "C");
$arraySize=4;
$b=new B();
$b->sortArray($arrayToSort,$sortType,$arraySize)
輸出結(jié)果如下所示:
0 = A 1 = B 2 = C 3 = f
簡化了可調(diào)用語法
可調(diào)用(callable)是可以被調(diào)用的 PHP 表達(dá)式,例如實(shí)例方法、靜態(tài)方法或可調(diào)用對象。例如,可調(diào)用可用于為方法調(diào)用創(chuàng)建簡短的表達(dá)式。在 PHP 8.1 中,可以用新的可調(diào)用語法:
AVariableCallableExpression(…)
AVariableCallableExpression 表示一個變量可調(diào)用表達(dá)式。省略號…包含在語法中。
為什么要使用新的可調(diào)用語法呢?讓我們通過一些示例來回顧一下傳統(tǒng)的可調(diào)用語法是什么樣子的:
$f1 = 'strlen'(…);
$f2 = [$someobj, 'somemethod'](…);
$f3 = [SomeClass::class, 'somestaticmethod'](…);
這有兩個問題:
語法涉及字符串和數(shù)組在創(chuàng)建可調(diào)用時,作用域不會被維護(hù)。為了演示這一點(diǎn),請考慮如下用于對數(shù)組進(jìn)行排序的腳本,其中 getSortArrayMethod() 方法返回 sortArray() 方法的可調(diào)用項,[$this,'sortArray'] 。<?php
class Sort {
private array $arrayToSort;
private string $sortType;
public function __construct($arrayToSort,$sortType)
{
$this->arrayToSort = $arrayToSort;
$this->sortType = $sortType;
}
public function getSortArrayMethod() {
return [$this, 'sortArray'];
}
private function sortArray() {
if ($this->sortType == "Asc") {
sort($this->arrayToSort);
foreach ($this->arrayToSort as $key => $val) {
echo "$key = $val ";
}
} elseif ($this->sortType == "Desc") {
rsort($this->arrayToSort);
foreach ($this->arrayToSort as $key => $val) {
echo "$key = $val ";
}
} else {
shuffle($this->arrayToSort);
foreach ($this->arrayToSort as $key => $val) {
echo "$key = $val ";
}
}
}
}
$sortType="Asc";
$arrayToSort=array("B", "A", "f", "C");
$sort = new Sort($arrayToSort,$sortType);
$c = $sort->getSortArrayMethod();
$c();
該腳本會生成如下的錯誤信息:
致命錯誤:未捕獲錯誤:調(diào)用私有方法Sort::sortArray()來自全局作用域
使用 Closure::fromCallable([$this, 'sortArray']) 而不是 [$this, 'sortArray'] 可以解決作用域問題,但使用 Closure::fromCallable 方**使調(diào)用變得冗長。新的可調(diào)用語法解決了作用域和語法冗長的問題。使用新的可調(diào)用語法,函數(shù)變?yōu)椋?/span>
public function getSortArrayMethod() {
return $this->sortArray(…);
}
數(shù)組根據(jù)輸出進(jìn)行排序:
0 = A 1 = B 2 = C 3 = f
新語法可以與涉及字符串和數(shù)組的傳統(tǒng)語法結(jié)合使用,以解決作用域問題。創(chuàng)建可調(diào)用的作用域?qū)⒈3植蛔儭?/span>
public function getSortArrayMethod() {
return [$this, 'sortArray'](…);
}
新的可調(diào)用語法也可以與靜態(tài)方法一起使用,如下面的腳本所示,該腳本包含一個靜態(tài)函數(shù)。
<?php
class Sort {
private array $arrayToSort;
private string $sortType;
public function __construct($arrayToSort,$sortType)
{
$this->arrayToSort = $arrayToSort;
$this->sortType = $sortType;
}
public function getStaticMethod() {
return Sort::aStaticFunction(…);
}
private static function aStaticFunction() {
}
}
$sortType="Asc";
$arrayToSort=array("B", "A", "f", "C");
$sort = new Sort($arrayToSort,$sortType);
$cStatic=$sort->getStaticMethod();
$cStatic();
輸出結(jié)果與之前的相同:
0 = A 1 = B 2 = C 3 =
以下是調(diào)用方法的等效方法:
return $this->sortArray(…);
return Closure::fromCallable([$this, 'sortArray']);
return [$this, 'sortArray'](…);
以下是調(diào)用靜態(tài)方法的等效方法:
return Sort::aStaticFunction(…);
return [Sort::class, 'aStaticFunction'](…);
return Closure::fromCallable([Sort::class, 'aStaticFunction']);
即使函數(shù)聲明了形參,也可以使用新的可調(diào)用語法。
<?php
class Sort {
private array $arrayToSort;
private string $sortType;
public function __construct($arrayToSort,$sortType)
{
$this->arrayToSort = $arrayToSort;
$this->sortType = $sortType;
}
public function getSortArrayMethod() {
return $this->sortArray(…);
}
private function sortArray(int $a,string $b) {
if ($this->sortType == "Asc") {
sort($this->arrayToSort);
foreach ($this->arrayToSort as $key => $val) {
echo "$key = $val ";
}
} elseif ($this->sortType == "Desc") {
rsort($this->arrayToSort);
foreach ($this->arrayToSort as $key => $val) {
echo "$key = $val ";
}
} else {
shuffle($this->arrayToSort);
foreach ($this->arrayToSort as $key => $val) {
echo "$key = $val ";
}
}
}
}
如果一個方法聲明了任意參數(shù),則必須使用它的參數(shù)來調(diào)用可調(diào)用對象。
$sortType="Asc";
$arrayToSort=array("B", "A", "f", "C");
$sort = new Sort($arrayToSort,$sortType);
$c = $sort->getSortArrayMethod();
$c(1,"A");
簡化語法可用于任意的 PHP Callable 表達(dá)式
簡化的可調(diào)用語法可以用于任意的 PHP 可調(diào)用表達(dá)式。用于對象創(chuàng)建的 new 運(yùn)算符不支持可調(diào)用語法,因?yàn)榭烧{(diào)用語法 AVariableCallableExpression(…) 沒有指定構(gòu)造函數(shù)參數(shù)的規(guī)定,這可能是必需的。以下是不支持的示例:
$sort = new Sort(…);
生成的錯誤信息為:
致命錯誤:不能為new表達(dá)式創(chuàng)建閉包
以下的腳本演示了受支持的所有可調(diào)用表達(dá)式。
<?php
class Sort {
private array $arrayToSort;
private string $sortType;
public function __construct($arrayToSort,$sortType)
{
$this->arrayToSort = $arrayToSort;
$this->sortType = $sortType;
}
public function getSortArrayMethod() {
return $this->sortArray(…);
}
public function getStaticMethod() {
return Sort::aStaticFunction(…);
}
public static function aStaticFunction() {
}
public function sortArray(int $a,string $b) {
if ($this->sortType == "Asc") {
sort($this->arrayToSort);
foreach ($this->arrayToSort as $key => $val) {
echo "$key = $val ";
}
} elseif ($this->sortType == "Desc") {
rsort($this->arrayToSort);
foreach ($this->arrayToSort as $key => $val) {
echo "$key = $val ";
}
} else {
shuffle($this->arrayToSort);
foreach ($this->arrayToSort as $key => $val) {
echo "$key = $val ";
}
}
}
public function __invoke() {}
}
$sortType="Asc";
$arrayToSort=array("B", "A", "f", "C");
$classStr = 'Sort';
$staticmethodStr = 'aStaticFunction';
$c1 = $classStr::$staticmethodStr(…);
$methodStr = 'sortArray';
$sort = new Sort($arrayToSort,$sortType);
$c2 = strlen(…);
$c3 = $sort(…); // 可調(diào)用對象
$c4 = $sort->sortArray(…);
$c5 = $sort->$methodStr(…);
$c6 = Sort::aStaticFunction(…);
$c7 = $classStr::$staticmethodStr(…);
// 傳統(tǒng)的可調(diào)用使用字符串,數(shù)組
$c8 = 'strlen'(…);
$c9 = [$sort, 'sortArray'](…);
$c10 = [Sort::class, 'aStaticFunction'](…);
$c11 = $sort->getSortArrayMethod();
$c11(1,"A");
$cStatic=$sort->getStaticMethod();
$cStatic();
尾逗號和可選/必選的參數(shù)順序
PHP 8.0 的另一個新特性是支持在函數(shù)的參數(shù)列表末尾添加一個尾逗號,以提高可讀性。任何尾逗號都將被忽略。尾逗號可能并不總是有用的,但如果參數(shù)列表很長,或者參數(shù)名稱很長,則可能會有用,因此可以垂直列出它們。閉包使用列表也支持尾逗號。
PHP 8.0 不支持在必選參數(shù)之前聲明可選參數(shù)。在必選參數(shù)之前聲明的可選參數(shù)都是隱式的必選參數(shù)。
下面的腳本演示了必選參數(shù)的隱式順序,以及尾逗號的使用。
<?php
function trailing_comma_example(
$the_very_first_arg_of_this_function,
$the_second_arg_of_this_function,
$the_third_arg_of_this_function = 1,
$the_fourth_arg_of_this_function,
$the_last_arg_of_this_function,
){ echo $the_third_arg_of_this_function; }
trailing_comma_example(1,2,null,3,4)
?>
輸出如下所示:
已棄用(不推薦):在必選參數(shù)$the_last_arg_of_this_function之前聲明的可選參數(shù)
$the_third_arg_of_tis_function將被隱式地視為必選參數(shù)
可空參數(shù)不會被視為可選參數(shù),可以使用 $param=null 形式或顯式可空類型在必選參數(shù)之前聲明,腳本如下所示:
<?php
class A {}
function fn1(A $a = null, $b) {}
function fn2(?A $a, $b) {}
fn1(new A,1);
fn2(null,1);
?>
命名函數(shù)形參和實(shí)參
PHP 8.0 除了已經(jīng)支持的位置形參和實(shí)參之外,還增加了對命名函數(shù)形參和實(shí)參的支持。命名參數(shù)在函數(shù)調(diào)用中的傳遞語法如下所示:
參數(shù)名稱:參數(shù)值
命名參數(shù)的一些好處如下所示:
可以為函數(shù)參數(shù)指定一個有意義的名稱,使它們能夠自我記錄按名稱傳遞時,參數(shù)與順序無關(guān)可以任意跳過默認(rèn)值。在下面的腳本中, array_hashtable 函數(shù)聲明了命名參數(shù)。 該函數(shù)傳遞的實(shí)參值可以帶參數(shù)名,也可以不帶參數(shù)名。當(dāng)傳遞位置實(shí)參時,使用函數(shù)形參聲明順序。但傳遞命名實(shí)參時,可以使用任意順序。
<?php
function array_hashtable($key1,$key2,$key3,$key4,$key5){
echo $key1.' '.$key2.' '.$key3.' '.$key4.' '.$key5;
echo "<br>";
}
// 使用位置實(shí)參:
array_hashtable(0, 10, 50, 20, 25);
// 使用命名實(shí)參:
array_hashtable(key2: 0, key5: 25, key1: 10, key4: 50, key3: 20);
?>
輸出結(jié)果為:
0 10 50 20 25
命名實(shí)參和位置實(shí)參可以在同一函數(shù)調(diào)用中使用。對相同的示例函數(shù) array_hashtable 一起使用混合參數(shù)調(diào)用。
<?php
function array_hashtable($key1,$key2,$key3,$key4,$key5){
echo $key1.' '.$key2.' '.$key3.' '.$key4.' '.$key5;
echo "<br>";
}
// 使用混合參數(shù):
array_hashtable(0, 10, 50, key5: 25, key4: 20);
?>
輸出結(jié)果為:
0 10 50 20 25
請注意,命名參數(shù)只能用于位置參數(shù)之后。下面的腳本顛倒了順序,在命名參數(shù)之后使用位置參數(shù):
<?php
function array_hashtable($key1,$key2,$key3,$key4,$key5){
echo $key1.' '.$key2.' '.$key3.' '.$key4.' '.$key5;
echo "<br>";
}
// Using mixed arguments:
array_hashtable(0, 10, key3: 25, 50, key5: 20);
?>
該腳本生成的錯誤信息為:
致命錯誤:不能在命名參數(shù)后使用位置參數(shù)
即使使用命名參數(shù),也不推薦在必選參數(shù)之前聲明可選參數(shù),腳本如下所示:
<?php
function array_hashtable($key1=0,$key2=10,$key3=20,$key4,$key5){
echo $key1.' '.$key2.' '.$key3.' '.$key4.' '.$key5;
echo "<br>";
}
// 使用混合參數(shù):
array_hashtable(1,2,key3: 25, key4: 1,key5: 20);
?>
輸出將包括已棄用(不推薦)信息:
已棄用(不推薦):在必選參數(shù)$key5之前聲明的可選參數(shù)$key1被隱式視為必選參數(shù)
已棄用(不推薦):在必選參數(shù)$key5之前聲明的可選參數(shù)$key2被隱式視為必選參數(shù)
已棄用(不推薦):在必選參數(shù)$key5之前聲明的可選參數(shù)$key3被隱式視為必選參數(shù)
當(dāng)在必選命名形參之后使用可選命名形參時,命名實(shí)參可用于跳過函數(shù)調(diào)用中的一個或多個可選形參,腳本如下所示:
<?php
function array_hashtable($key1,$key2,$key3=20,$key4=50,$key5=10){
echo $key1.' '.$key2.' '.$key3.' '.$key4.' '.$key5;
echo "<br>";
}
// 使用混合參數(shù):
array_hashtable(key1:1, key2:2,key4: 25);
?>
輸出結(jié)果為:
1 2 20 25 10
你可以只使用可選參數(shù)的子集來調(diào)用函數(shù),而不用考慮它們的順序。
<?php
function array_hashtable($key1=0,$key2=10,$key3=20,$key4=50,$key5=10){
echo $key1.' '.$key2.' '.$key3.' '.$key4.' '.$key5;
echo "<br>";
}
// 使用混合參數(shù):
array_hashtable(1,2,key4: 25);
?>
輸出結(jié)果如下所示:
1 2 20 25 10
即使使用可選參數(shù)的子集調(diào)用函數(shù),也不能在命名參數(shù)之后使用位置參數(shù),腳本如下所示:
<?php
function array_hashtable($key1=0,$key2=10,$key3=20,$key4=50,$key5=10){
echo $key1.' '.$key2.' '.$key3.' '.$key4.' '.$key5;
echo "<br>";
}
// Using mixed arguments:
array_hashtable(1,2,key4: 25,5);
?>
生成的錯誤信息以下所示:
致命錯誤:不能在命名參數(shù)后使用位置參數(shù)
PHP 8.1 改進(jìn)了命名實(shí)參特性,在解包實(shí)參后支持命名實(shí)參,腳本如下所示:
<?php
function array_hashtable($key1,$key2,$key3=30,$key4=40,$key5=50){
echo $key1.' '.$key2.' '.$key3.' '.$key4.' '.$key5;
echo "<br>";
}
echo array_hashtable(…[10, 20], key5: 40);
echo array_hashtable(…['key2' => 2, 'key1' => 2], key4: 50);
?>
輸出如下所示:
10 20 30 40 40
2 2 30 50 50
但是,命名的參數(shù)不能蓋前面的參數(shù),腳本如下所示:
<?php
function array_hashtable($key1,$key2,$key3=30,$key4=40,$key5=50){
echo $key1.' '.$key2.' '.$key3.' '.$key4.' '.$key5;
echo "<br>";
}
echo array_hashtable(…[10, 20], key2: 40);
?>
輸出如下所示:
致命錯誤:未捕獲錯誤:命名參數(shù)$key2覆蓋上一個參數(shù)。
非靜態(tài)方法不能被靜態(tài)調(diào)用
在 PHP 8.0 之前,如果在靜態(tài)上下文中調(diào)用非靜態(tài)方法,或者靜態(tài)調(diào)用,則只會收到一條已棄用(不推薦)的信息。使用 8.0,你現(xiàn)在會收到一條錯誤信息。此外, $this 在靜態(tài)上下文中是未定義的。為了演示這一點(diǎn),請考慮如下的腳本,其中使用靜態(tài)語法 A::aNonStaticMethod() 調(diào)用了非靜態(tài)方法 aNonStaticMethod() 。
<?php
class A
{
function aNonStaticMethod()
{
}
}
A::aNonStaticMethod();
如果你運(yùn)行這個腳本,將會得到如下的錯誤信息:
未捕獲錯誤:非靜態(tài)方法A::aNonStaticMethod()不能被靜態(tài)調(diào)用
纖程
PHP 8.1 添加了對纖程(Fiber)多任務(wù)的支持。纖程是一個可中斷的函數(shù),它具有自己的堆棧。纖程可以從調(diào)用堆棧中的任何位置掛起,第二再恢復(fù)。新的 Fiber 類是一個 final 類,它支持以下的公共方法:
方法
描述
__construct(callable $callback) <br>
創(chuàng)建新Fiber實(shí)例的構(gòu)造函數(shù)。 該參數(shù)是啟動纖程時要調(diào)用的可調(diào)用對象。 提供給Fiber::start()的參數(shù)將作為給定可調(diào)用對象的參數(shù)提供。 可調(diào)用對象根本不需要調(diào)用Fiber::suspend(),或者即使調(diào)用也不需要直接調(diào)用。對Fiber::suspend()的調(diào)用可能在調(diào)用堆棧中嵌套很深。
start(mixed …$args): mixed
啟動纖程。該方法在纖程掛起或終止時返回。在構(gòu)造纖程時,為所使用的可調(diào)用函數(shù)提供了可變的參數(shù)列表。如果纖程返回,則從第一個掛起點(diǎn)返回混合值或返回NULL。如果調(diào)用該方法時纖程已經(jīng)啟動,則會拋出FiberError錯誤。
resume(mixed $value = null): mixed
恢復(fù)纖程,從Fiber::suspend()返回給定的混合值。 當(dāng)纖程掛起或終止時返回。 返回的混合值實(shí)際上是從下一個掛起點(diǎn)返回的,如果纖程返回,則返回NULL。 如果纖程尚未啟動、正在運(yùn)行或已終止,則拋出FiberError錯誤。
throw(Throwable $exception): mixed
將給定的異常從Fiber::suspend()拋出到纖程中。 當(dāng)纖程掛起或終止時返回。 參數(shù)是Throwable $exception。 返回的混合值實(shí)際上是從下一個掛起點(diǎn)返回的,如果纖程返回,則返回NULL。 如果纖程尚未啟動、正在運(yùn)行或已終止,則拋出FiberError錯誤。
getReturn(): mixed
獲取纖程回調(diào)的混合返回值。 如果纖程沒有返回語句,則返回NULL。 如果纖程未終止或纖程拋出異常,則拋出FiberError錯誤。
isStarted(): bool
如果纖程已經(jīng)啟動,則返回布爾值True。
isSuspended(): bool
如果纖程已掛起,則返回布爾值True。
isRunning(): bool
如果纖程正在運(yùn)行,則返回布爾值True。
isTerminated(): bool
如果纖程已終止,則返回布爾值True。
static suspend(mixed $value = null): mixed
掛起纖程。 返回對Fiber->start()、Fiber->resume() 或 Fiber->throw() 的調(diào)用執(zhí)行??梢允褂肍iber::resume()或Fiber::throw()恢復(fù)纖程。不能從纖程外的主線程調(diào)用。 參數(shù)是從Fiber::resume()或 Fiber::throw()返回的混合值$value。返回的混合值提供給Fiber::resume()。<br>如果不在纖程內(nèi)(即,如果從主線程調(diào)用),則拋出FiberError錯誤。
static getCurrent(): ?Fiber
返回當(dāng)前正在執(zhí)行的纖程實(shí)例,如果在主線程中則返回NULL。
纖程只能啟動一次,但可以掛起并恢復(fù)多次。下面的腳本通過使用纖程在數(shù)組上執(zhí)行不同類型的排序來演示多任務(wù)處理。纖程在每次排序后都會掛起,第二再恢復(fù)執(zhí)行不同類型的排序。
<?php
$fiber = new Fiber(function (array $arr): void {
sort($arr);
foreach ($arr as $key => $val) {
echo "$key = $val ";
}
echo "<br/>";
Fiber::suspend();
rsort($arr);
foreach ($arr as $key => $val) {
echo "$key = $val ";
}
echo "<br/>";
Fiber::suspend();
shuffle($arr);
foreach ($arr as $key => $val) {
echo "$key = $val ";
}
});
$arrayToSort=array("B", "A", "f", "C");
$value = $fiber->start($arrayToSort);
$fiber->resume();
$fiber->resume();
?>
輸出如下所示:
0 = A 1 = B 2 = C 3 = f
0 = f 1 = C 2 = B 3 = A
0 = C 1 = f 2 = A 3 = B
如果纖程在第一次掛起后沒有再恢復(fù),則只進(jìn)行一種類型的排序,這可以通過注釋掉對 resume() 的兩次調(diào)用來實(shí)現(xiàn)。
//$fiber->resume();
//$fiber->resume();
輸出的是第一次排序的結(jié)果:
0 = A 1 = B 2 = C 3 = f
Stringable 接口和 __toString()
PHP 8.0 引入了一個名為 Stringable 的新接口,它只提供一個方法 __toString() 。 __toString() 方法如果在類中提供,將隱式實(shí)現(xiàn) Stringable 接口??紤]提供 __toString() 方法的類 A。
<?php
class A {
public function __toString(): string {
return " ";
}
}
echo (new A() instanceof Stringable);
該腳本從 Stringable 的類型檢查中返回 1。
然而,反之則不然。如果類實(shí)現(xiàn)了 Stringable 接口,則必須顯式提供 __toString() 方法,因?yàn)樵摲椒ú粫詣犹砑?,比如?/span>
<?php
class A implements Stringable {
public function __toString(): string { }
}
新的標(biāo)準(zhǔn)庫函數(shù)
PHP 8 引入了許多屬于其標(biāo)準(zhǔn)庫的新函數(shù)。
str_contains 函數(shù)返回一個 bool 值,用于指示作為第一個參數(shù)的字符串是否包含作為第二個參數(shù)的字符串。以下腳本將返回 false :
<?php
if (str_contains('haystack', 'needle')) {
echo true;
} else {
echo false;
}
下面的腳本返回 1,或 true:
<?php
if (str_contains('haystack', 'hay')) {
echo true;
}else {
echo "false";
}
str_starts_with 函數(shù)返回一個bool 值 ,指示作為第一個參數(shù)的字符串是否以作為第二個參數(shù)的字符串開頭。以下腳本將返回 false 。
<?php
if (str_contains('haystack', 'hay')) {
echo true;
}else {
echo "false";
}
下面的腳本將返回 1,或 true。
<?php
if (str_starts_with('haystack', 'needle')) {
echo true;
} else {
echo false;
}
str_ends_with 函數(shù)返回一個bool 值 ,指示作為第一個參數(shù)的字符串是否以作為第二個參數(shù)的字符串結(jié)尾。以下腳本將返回 false 。
<?php
if (str_starts_with('haystack', 'needle')) {
echo true;
} else {
echo false;
}
下面的腳本將返回 1,或 true。
<?php
if (str_starts_with('haystack', 'hay')) {
echo true;
} else {
echo false;
}
fdiv 函數(shù)將兩個數(shù)字相除并返回一個 float 值,腳本如下所示:
<?php
var_dump(fdiv(1.5, 1.3));
var_dump(fdiv(10, 2));
var_dump(fdiv(5.0, 0.0));
var_dump(fdiv(-2.0, 0.0));
var_dump(fdiv(0.0, 0.0));
var_dump(fdiv(5.0, 1.0));
var_dump(fdiv(10.0, 2));
輸出為:
float(1.1538461538461537)
float(5)
float(INF)
float(-INF)
float(NAN)
float(5)
float(5)
fdatasync 函數(shù)在 Windows 上的別名為 fsync ,用于將數(shù)據(jù)同步到文件上的流中。為了演示它的用法,在包含要運(yùn)行的 PHP 腳本的腳本目錄中創(chuàng)建一個空文件 test.txt 。運(yùn)行腳本:
<?php
$file = 'test.txt';
$stream = fopen($file, 'w');
fwrite($stream, 'first line of data');
fwrite($stream, "\r\n");
fwrite($stream, 'second line of data');
fwrite($stream, 'third line of data');
fdatasync($stream);
fclose($stream);
隨后,打開 test.txt 文件會發(fā)現(xiàn)包含如下的文本:
first line of data
second line of data
third line of data
array_is_list 函數(shù)返回布爾值,用于指示給定的數(shù)組是否為列表。數(shù)組必須從 0 開始,鍵必須是連續(xù)的整數(shù),并且順序正確。下面的腳本演示了 array_is_list 函數(shù):
<?php
echo array_is_list([]);
echo array_is_list(['1', 2, 3]);
echo array_is_list([0 => 'a', 'b']);
echo array_is_list([1 => 'a', 'b']); // false
echo array_is_list([1 => 'a', 0 => 'b']); // false
echo array_is_list([0 => 'a', 'b' => 'b']); // false
echo array_is_list([0 => 'a', 2 => 'b']); // false
輸出為:
1
1
1
魔術(shù)方法必須要有正確的簽名
魔術(shù)方法是 PHP 中用于覆蓋默認(rèn)**作的特殊方法。它們包括如下的方法,其中構(gòu)造函數(shù) __construct() 可能是大家最熟悉的:
__construct(),
__destruct(),
__call(),
__callStatic(),
__get(),
__set(),
__isset(),
__unset(),
__sleep(),
__wakeup(),
__serialize(),
__unserialize(),
__toString(),
__invoke(),
__set_state(),
__clone(),
__debugInfo()
從 PHP 8.0 開始,魔術(shù)方法定義的簽名必須要是正確的,這意味著如果在方法參數(shù)或返回類型中使用類型聲明,則它們必須與文檔中的聲明相同。新的 __toString() 方法的返回類型必須要聲明為 string 。下面的演示將返回類型聲明為 int :
<?php
class A {
public function __toString(): int {
}
}
將生成如下的錯誤信息:
致命錯誤:A::__toString():返回類型在聲明時必須是字符串
但是,未通過定義聲明返回類型的函數(shù)(如構(gòu)造函數(shù))不能聲明返回類型,即使是 void 返回類型也不行。示例如下腳本所示:
<?php
class A {
public function __construct():void
{
}
}
該腳本將返回如下的錯誤信息:
致命錯誤:方法A::__construct()不能聲明返回類型
所有魔術(shù)方法,除了少數(shù)例外(例如 __construct() )外,都必須聲明為具有公共可見性。為了演示這一點(diǎn),聲明了一個帶有 private 可見性的 __callStatic 。
<?php
class A {
private static function __callStatic(string $name, array $arguments) {}
}
輸出的警告信息為:
警告:魔術(shù)方法A::__callStatic()必須要具有公共可見性
盡管可以省略混合返回類型,但方法簽名也必須相同。例如,在下面的腳本中,類 A 聲明了 __callStatic 而沒有指定其返回類型,而類 B 將其第一個參數(shù)定義為int :
<?php
class A {
public static function __callStatic(string $name, array $arguments) {}
class B {
public static function __callStatic(int $name, array $arguments) {}
}
輸出的錯誤信息如下所示:
致命錯誤:B::__callStatic():參數(shù) #1 ($name) 在聲明時必須為字符串類型
返回類型與內(nèi)部類的兼容性
在 PHP 8.1 中,大多數(shù)內(nèi)部方法,即內(nèi)部類中的方法,都已經(jīng)“試探性地”開始聲明返回類型。試探性地暗示,雖然在 8.1 中只會引發(fā)不推薦(Deprecation)通知,但在 9.0 版中,則會輸出錯誤條件信息。因此,任何擴(kuò)展類都必須聲明與內(nèi)部類相兼容的返回類型,否則將會引發(fā)已棄用(不推薦)通知。為了演示這一點(diǎn),擴(kuò)展內(nèi)部類 Directory 并重新聲明沒有返回類型的函數(shù) read() :
<?php
class A extends Directory {
public function read() { }
}
該腳本將生成已棄用(不推薦)通知:
<?php
class A extends Directory {
public function read():string { return ""; }
}
但是,以下腳本是可以的:
<?php
class A extends Directory {
public function read():string { return ""; }
}
添加 #[\ReturnTypeWillChange] 屬性能抑制已棄用(不推薦)通知:
<?php
class A extends Directory {
#[\ReturnTypeWillChange]
public function read() { }
}
\SensitiveParameter 屬性
雖然包含有關(guān)方法參數(shù)的詳細(xì)信息的異常堆棧跟蹤對調(diào)試非常有用,但你可能不希望輸出某些敏感參數(shù)的參數(shù)值,例如與密碼和憑據(jù)關(guān)聯(lián)的參數(shù)值。PHP 8.2 引入了一個名為 \SensitiveParameter 的新屬性,這樣,如果使用 \SensitivyParameter 屬性注解方法的參數(shù),則該參數(shù)的值不會在異常堆棧跟蹤中輸出。
為了演示這一點(diǎn),考慮下面的腳本,其中函數(shù) f1 具有與 \SensitiveParameter 屬性關(guān)聯(lián)的參數(shù) $password 。
<?php
function f1(
$param1 = 1,
#[\SensitiveParameter] $password = “s@5f_u7”,
$param3 = null
) {
throw new \Exception('Error');
}
為了演示 \SensitiveParameter 特性,該函數(shù)只是拋出一個異常。調(diào)用函數(shù):
f1(param3: 'a');
請注意,異常堆棧跟蹤不包含 $password 參數(shù)的值,而是列出了 Object(SensitiveParameterValue) 。
Stack trace: #0 : f1(1, Object(SensitiveParameterValue), 'a') #1 {main}
內(nèi)置函數(shù)棄用/增強(qiáng)
內(nèi)置函數(shù) utf8_encode() 和 utf8_decode() 經(jīng)常被誤解,因?yàn)樗鼈兊拿Q意味著對任何字符串進(jìn)行編碼/解碼。實(shí)際上,這些函數(shù)僅用于編碼/解碼 ISO8859-1,即“Latin-1”字符串。此外,它們生成的錯誤信息對于調(diào)試來說描述性不夠。PHP 8.2 已經(jīng)棄用了這些函數(shù)。下面的腳本使用了它們:
<?php
$string_to_encode = "\x7A\x6A\xdB";
$utf8_string = utf8_encode($string_to_encode);
echo bin2hex($utf8_string), "\n";
$utf8_string = "\x6A\x6B\xD3\xCB";
$decoded_string = utf8_decode($utf8_string);
echo bin2hex($decoded_string), "\n";
對于 PHP 8.2,會輸出已棄用(不推薦)通知:
已棄用(不推薦):函數(shù)utf8_encode()已棄用
已棄用(不推薦):函數(shù)utf8_decode()已棄用
在 PHP 8.2 中,函數(shù) iterator_count 和 iterator_to_array 接受所有可迭代的對象。 iterator_to_array() 函數(shù)將迭代器的元素**到數(shù)組中。 iterator_count() 函數(shù)對數(shù)組的元素進(jìn)行計數(shù)。這些函數(shù)接受一個 $iterator 作為第一個參數(shù)。在 PHP 8.2 中,$iterator 參數(shù)的類型已從 Traversable 擴(kuò)展為 Traversable|array ,以便接受任意的可迭代值。
下面的腳本演示了它們在 arrays 和 Traversables 中的使用。
<?php
$a=array('1'=>'one', 'two', 'three', 'four');
$iterator = new ArrayIterator($a);
var_dump(iterator_to_array($iterator, true));
var_dump(iterator_to_array($a, true));
var_dump(iterator_count($iterator));
var_dump(iterator_count($a));
輸出如下所示:
array(4) { [1]=> string(3) "one" [2]=> string(3) "two" [3]=> string(5) "three" [4]=> string(4) "four" }
array(4) { [1]=> string(3) "one" [2]=> string(3) "two" [3]=> string(5) "three" [4]=> string(4) "four" }
int(4)
int(4)
小編綜合來說
在這篇 PHP 8 系列文章中,我們討論了與函數(shù)和方法相關(guān)的新特性,其中最突出的是命名函數(shù)的形參/實(shí)參、簡化的可調(diào)用語法和被稱為纖程(Fiber)的可中斷函數(shù)。
在本系列的下一篇文章中,我們將介紹 PHP 類型系統(tǒng)的新特性。
PHP 8:注解、match 表達(dá)式及其他改進(jìn)
PHP 8:類和枚
拓展知識:
原創(chuàng)文章,作者:九賢生活小編,如若轉(zhuǎn)載,請注明出處:http://xiesong.cn/4643.html