<p>類型聲明(míng)可以用(yòng)于函數的參數、返回值,PHP 7.4.0 起還可以用(yòng)于類的屬性,來(lái)顯性的指定需要的類型,如果預期類型在調用(yòng)時(shí)不匹配,則會(huì)抛出一個 TypeError 異常。
PHP 支持各種單一類型,除了(le) resource 之外(wài),都可以用(yòng)于用(yòng)戶級别類型聲明(míng)。這(zhè)個頁面包含了(le)不同類型間的可用(yòng)性變更日志以及在類型聲明(míng)中用(yòng)法的文(wén)檔。
注意:
當類實現(xiàn)了(le)接口方法或者重新實現(xiàn)了(le)父級類中定義的方法時(shí),必須與上(shàng)述定義兼容。如果方法遵循方差規則,則兼容該方法。
更新日志
版本 | 說明(míng) |
---|---|
8.2.0 | 新增對(duì) DNF 類型的支持。 |
8.2.0 | 新增對(duì) literal 類型 true 的支持。 |
8.2.0 | 現(xiàn)在可以單獨使用(yòng) null 和(hé) false。 |
8.1.0 | 新增對(duì)交集類型的支持。 |
8.1.0 | 棄用(yòng) void 函數通過引用(yòng)返回。 |
8.1.0 | 新增對(duì)返回類型 never 的支持。 |
8.0.0 | 新增對(duì) mixed 類型的支持。 |
8.0.0 | 新增對(duì)返回類型 static 的支持。 |
8.0.0 | 新增對(duì)聯合類型的支持。 |
7.2.0 | 新增對(duì) object 類型的支持。 |
7.1.0 | 新增對(duì) iterable 類型的支持。 |
7.1.0 | 新增對(duì) void 類型的支持。 |
7.1.0 | 新增對(duì)可爲 null 類型的支持。 |
基本類型使用(yòng)說明(míng) ¶
Base types have straight forward behaviour with some minor caveats which are described in this section.
标量類型 ¶
警告
标量類型(bool、int、float、string)不支持别名。别名反而會(huì)視(shì)爲類或接口名。例如,使用(yòng) boolean 作(zuò)爲類型聲明(míng),将要求值是 instanceof 類或接口 boolean,而不是類型 bool。
<?php
function test(boolean $param) {}
test(true);
?>
以上(shàng)例程在 PHP 8 中的輸出:
Warning: "boolean" will be interpreted as a class name. Did you mean "bool"? Write "\boolean" to suppress this warning in /in/9YrUX on line 2
Fatal error: Uncaught TypeError: test(): Argument #1 ($param) must be of type boolean, bool given, called in - on line 3 and defined in -:2
Stack trace:
#0 -(3): test(true)
#1 {main}
thrown in - on line 2
void ¶
注意:
從(cóng) PHP 8.1.0 起棄用(yòng) void 函數通過引用(yòng)返回,因爲這(zhè)樣的函數自(zì)相矛盾。在此之前調用(yòng)時(shí)總是會(huì)發出如下(xià) E_NOTICE:Only variable references should be returned by reference。
<?php
function &test(): void {}
?>
Callable 類型 ¶
此類型不能(néng)用(yòng)于類屬性的類型聲明(míng)。
注意: 無法指定函數的簽名。
通過引用(yòng)傳遞的參數類型 ¶
如果通過引用(yòng)傳遞的參數有類型聲明(míng),則變量的類型僅在調用(yòng)函數時(shí)檢查,返回時(shí)不會(huì)檢查。這(zhè)意味着函數可以改變引用(yòng)變量的類型。
示例 #1 通過引用(yòng)傳遞的參數類型
<?php
function array_baz(array &$param)
{
$param = 1;
}
$var = [];
array_baz($var);
var_dump($var);
array_baz($var);
?>
以上(shàng)例程的輸出類似于:
int(1)
Fatal error: Uncaught TypeError: array_baz(): Argument #1 ($param) must be of type array, int given, called in - on line 9 and defined in -:2
Stack trace:
#0 -(9): array_baz(1)
#1 {main}
thrown in - on line 2
複合類型使用(yòng)說明(míng) ¶
複合類型聲明(míng)有幾個限制,并且在編譯時(shí)執行冗餘檢查以避免簡單的錯誤。
警告
在 PHP 8.2 之前,也(yě)就是沒引入 DNF 之前,交集類型和(hé)聯合類型不能(néng)組合使用(yòng)。
聯合類型 ¶
警告
在一個聯合類型中不能(néng)同時(shí)用(yòng)兩個 literal 類型 false 和(hé) true。而是使用(yòng) bool 替代。
警告
在 PHP 8.2.0 之前,由于 false 和(hé) null 不能(néng)作(zuò)爲獨立的類型使用(yòng),因此不允許僅由這(zhè)些(xiē)類型組成聯合類型。這(zhè)還包括以下(xià)類型:false、false|null, 和(hé) ?false。
可爲 null 類型語法糖
單個基本類型聲明(míng)可以通過在類型前添加問号(?)來(lái)标記可爲 null。因此 ?T 和(hé) T|null 是相同的。
注意: 該語法自(zì) PHP 7.1.0 起支持,且早于完整的(generalized)聯合類型支持。
注意:
也(yě)可以通過設置參數的參數的默認值爲 null 來(lái)實現(xiàn)允許爲 null。但(dàn)并不建議(yì)這(zhè)麽做,因爲如果在子類中更改了(le)默認值,會(huì)引發類型兼容沖突,需要将 null 類型添加到(dào)類型聲明(míng)中。
示例 #2 使參數可以爲 null 的舊方法
<?php
class C {}
function f(C $c = null) {
var_dump($c);
}
f(new C);
f(null);
?>
以上(shàng)例程會(huì)輸出:
object(C)#1 (0) {
}
NULL
重複冗餘的類型 ¶
爲了(le)能(néng)捕獲複合類型聲明(míng)中的簡單錯誤,不需要類加載檢測到(dào)的冗餘類型将導緻編譯時(shí)錯誤。包含:
解析出來(lái)的類型隻能(néng)出現(xiàn)一次。例如這(zhè)樣的類型 int|string|INT 或 Countable&Traversable&COUNTABLE 會(huì)導緻錯誤。
使用(yòng) mixed 會(huì)導緻錯誤。
對(duì)于聯合類型:
使用(yòng)了(le) bool 時(shí)就不能(néng)再附帶使用(yòng) false 或者 true。
使用(yòng)了(le) object 時(shí)就不能(néng)再附帶使用(yòng) class 類型。
使用(yòng)了(le) iterable 時(shí),不能(néng)再附帶使用(yòng) array 和(hé) Traversable。
對(duì)于交集類型:
使用(yòng) class-type 以外(wài)的類型會(huì)導緻錯誤。
使用(yòng) self、parent 或 static 都會(huì)導緻錯誤。
DNF 類型:
If a more generic type is used, the more restrictive one is redundant.
使用(yòng)兩個相同的交集類型。
注意: 不過它不能(néng)确保類型最小(xiǎo)化,因爲要達到(dào)這(zhè)樣的效果,還要加載使用(yòng)類型的 class。
例如,假設 A 和(hé) B 都是一個類的别名, 而 A|B 仍然是有效的,哪怕它可以被簡化爲 A 或 B。 同樣的,如果 B extends A {},那 A|B 仍然是有效的聯合類型,盡管它可以被簡化爲 A。
<?php
function foo(): int|INT {} // 不允許
function foo(): bool|false {} // 不允許
function foo(): int&Traversable {} // 不允許
function foo(): self&Traversable {} // 不允許
use A as B;
function foo(): A|B {} // 不允許 ("use" 是名稱解析的一部分)
function foo(): A&B {} // 不允許 ("use" 是名稱解析的一部分)
class_alias('X', 'Y');
function foo(): X|Y {} // 允許 (運行時(shí)才能(néng)知(zhī)道(dào)重複性)
function foo(): X&Y {} // 允許 (運行時(shí)才能(néng)知(zhī)道(dào)重複性)
?>
範例 ¶
示例 #3 基礎類類型聲明(míng)
<?php
class C {}
class D extends C {}
// 沒有繼承 C。
class E {}
function f(C $c) {
echo get_class($c)."\n";
}
f(new C);
f(new D);
f(new E);
?>
以上(shàng)例程在 PHP 8 中的輸出:
C
D
Fatal error: Uncaught TypeError: f(): Argument #1 ($c) must be of type C, E given, called in /in/gLonb on line 14 and defined in /in/gLonb:8
Stack trace:
#0 -(14): f(Object(E))
#1 {main}
thrown in - on line 8
示例 #4 基礎接口類型聲明(míng)
<?php
interface I { public function f(); }
class C implements I { public function f() {} }
// 沒有實現(xiàn)(implement)I。
class E {}
function f(I $i) {
echo get_class($i)."\n";
}
f(new C);
f(new E);
?>
以上(shàng)例程在 PHP 8 中的輸出:
C
Fatal error: Uncaught TypeError: f(): Argument #1 ($i) must be of type I, E given, called in - on line 13 and defined in -:8
Stack trace:
#0 -(13): f(Object(E))
#1 {main}
thrown in - on line 8
示例 #5 基礎返回類型聲明(míng)
<?php
function sum($a, $b): float {
return $a + $b;
}
// Note that a float will be returned.
var_dump(sum(1, 2));
?>
以上(shàng)例程會(huì)輸出:
float(3)
示例 #6 返回對(duì)象
<?php
class C {}
function getC(): C {
return new C;
}
var_dump(getC());
?>
以上(shàng)例程會(huì)輸出:
object(C)#1 (0) {
}
示例 #7 可爲 null 參數類型聲明(míng)
<?php
class C {}
function f(?C $c) {
var_dump($c);
}
f(new C);
f(null);
?>
以上(shàng)例程會(huì)輸出:
object(C)#1 (0) {
}
NULL
示例 #8 可爲 null 返回類型聲明(míng)
<?php
function get_item(): ?string {
if (isset($_GET['item'])) {
return $_GET['item'];
} else {
return null;
}
}
?>
嚴格類型 ¶
默認如果可能(néng),PHP 會(huì)強制轉化不合适的類型爲想要的标量類型。 比如,參數想要 string,傳入的是 int, 則會(huì)獲取 string 類型的變量。
可以按文(wén)件開(kāi)啓嚴格模式。 在嚴格模式下(xià),隻能(néng)接受完全匹配的類型,否則會(huì)抛出 TypeError。 唯一的例外(wài)是 int 值也(yě)可以傳入聲明(míng)爲 float 的類型。
警告
通過内部函數調用(yòng)函數時(shí),不會(huì)受 strict_types 聲明(míng)影響。
要開(kāi)啓嚴格模式,使用(yòng) declare 開(kāi)啓 strict_types:
注意:
文(wén)件開(kāi)啓嚴格類型後的内部調用(yòng)函數将應用(yòng)嚴格類型, 而不是在聲明(míng)函數的文(wén)件内開(kāi)啓。 如果文(wén)件沒有聲明(míng)開(kāi)啓嚴格類型,而被調用(yòng)的函數所在文(wén)件有嚴格類型聲明(míng), 那将遵循調用(yòng)者的設置(開(kāi)啓類型強制轉化), 值也(yě)會(huì)強制轉化。
注意:
隻有爲标量類型的聲明(míng)開(kāi)啓嚴格類型。
示例 #9 參數值的嚴格類型
<?php
declare(strict_types=1);
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
?>
以上(shàng)例程在 PHP 8 中的輸出:
int(3)
Fatal error: Uncaught TypeError: sum(): Argument #1 ($a) must be of type int, float given, called in - on line 9 and defined in -:4
Stack trace:
#0 -(9): sum(1.5, 2.5)
#1 {main}
thrown in - on line 4
示例 #10 參數值的類型強制轉化
<?php
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
// 以下(xià)會(huì)強制轉化爲整型,注意以下(xià)内容輸出!
var_dump(sum(1.5, 2.5));
?>
以上(shàng)例程會(huì)輸出:
int(3)
int(3)
示例 #11 返回值的嚴格類型
<?php
declare(strict_types=1);
function sum($a, $b): int {
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1, 2.5));
?>
以上(shàng)例程會(huì)輸出:
int(3)
Fatal error: Uncaught TypeError: sum(): Return value must be of type int, float returned in -:5
Stack trace:
#0 -(9): sum(1, 2.5)
#1 {main}
thrown in - on line 5</p>
網站(zhàn)建設開(kāi)發|APP設計(jì)開(kāi)發|小(xiǎo)程序建設開(kāi)發