做(zuò)自(zì)由與創造的先行(xíng)者

類型聲明(míng)

PHP中文手冊

<p>類型聲明(míng)可(kě)以用于函數(shù)的參數(shù)、返回值,PHP 7.4.0 起還可(kě)以用于類的屬性,來顯性的指定需要(yào)的類型,如(rú)果預期類型在調用時(shí)不匹配,則會抛出一(yī)個 TypeError 異常。

PHP 支持各種單一(yī)類型,除了(le) resource 之外(wài),都(dōu)可(kě)以用于用戶級别類型聲明(míng)。這(zhè)個頁面包含了(le)不同類型間(jiān)的可(kě)用性變更日志以及在類型聲明(míng)中用法的文檔。

注意:

當類實現了(le)接口方法或者重新實現了(le)父級類中定義的方法時(shí),必須與上(shàng)述定義兼容。如(rú)果方法遵循方差規則,則兼容該方法。

更新日志

版本 說明(míng)
8.2.0 新增對 DNF 類型的支持。
8.2.0 新增對 literal 類型 true 的支持。
8.2.0 現在可(kě)以單獨使用 null 和(hé) false
8.1.0 新增對交集類型的支持。
8.1.0 棄用 void 函數(shù)通(tōng)過引用返回。
8.1.0 新增對返回類型 never 的支持。
8.0.0 新增對 mixed 類型的支持。
8.0.0 新增對返回類型 static 的支持。
8.0.0 新增對聯合類型的支持。
7.2.0 新增對 object 類型的支持。
7.1.0 新增對 iterable 類型的支持。
7.1.0 新增對 void 類型的支持。
7.1.0 新增對可(kě)為(wèi) null 類型的支持。

基本類型使用說明(míng) ¶

Base types have straight forward behaviour with some minor caveats which are described in this section.

标量類型 ¶

警告

标量類型(bool、int、float、string)不支持别名。别名反而會視(shì)為(wèi)類或接口名。例如(rú),使用 boolean 作(zuò)為(wèi)類型聲明(míng),将要(yào)求值是 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 起棄用 void 函數(shù)通(tōng)過引用返回,因為(wèi)這(zhè)樣的函數(shù)自(zì)相矛盾。在此之前調用時(shí)總是會發出如(rú)下(xià) E_NOTICE:Only variable references should be returned by reference。

<?php

function &test(): void {}

?>

Callable 類型 ¶

此類型不能(néng)用于類屬性的類型聲明(míng)。

注意: 無法指定函數(shù)的簽名。

通(tōng)過引用傳遞的參數(shù)類型 ¶

如(rú)果通(tōng)過引用傳遞的參數(shù)有類型聲明(míng),則變量的類型僅在調用函數(shù)時(shí)檢查,返回時(shí)不會檢查。這(zhè)意味着函數(shù)可(kě)以改變引用變量的類型。

示例 #1 通(tōng)過引用傳遞的參數(shù)類型

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

複合類型使用說明(míng) ¶

複合類型聲明(míng)有幾個限制,并且在編譯時(shí)執行(xíng)冗餘檢查以避免簡單的錯誤。

警告

在 PHP 8.2 之前,也就是沒引入 DNF 之前,交集類型和(hé)聯合類型不能(néng)組合使用。

聯合類型 ¶

警告

在一(yī)個聯合類型中不能(néng)同時(shí)用兩個 literal 類型 false 和(hé) true。而是使用 bool 替代。

警告

在 PHP 8.2.0 之前,由于 false 和(hé) null 不能(néng)作(zuò)為(wèi)獨立的類型使用,因此不允許僅由這(zhè)些類型組成聯合類型。這(zhè)還包括以下(xià)類型:false、false|null, 和(hé) ?false。

可(kě)為(wèi) null 類型語法糖

單個基本類型聲明(míng)可(kě)以通(tōng)過在類型前添加問(wèn)号(?)來标記可(kě)為(wèi) null。因此 ?T 和(hé) T|null 是相同的。

注意: 該語法自(zì) PHP 7.1.0 起支持,且早于完整的(generalized)聯合類型支持。

注意:

也可(kě)以通(tōng)過設置參數(shù)的參數(shù)的默認值為(wèi) null 來實現允許為(wèi) null。但(dàn)并不建議(yì)這(zhè)麽做(zuò),因為(wèi)如(rú)果在子類中更改了(le)默認值,會引發類型兼容沖突,需要(yào)将 null 類型添加到類型聲明(míng)中。

示例 #2 使參數(shù)可(kě)以為(wèi) null 的舊(jiù)方法

<?php

class C {}

function f(C $c = null) {

var_dump($c);

}

f(new C);

f(null);

?>

以上(shàng)例程會輸出:

object(C)#1 (0) {

}

NULL

重複冗餘的類型 ¶

為(wèi)了(le)能(néng)捕獲複合類型聲明(míng)中的簡單錯誤,不需要(yào)類加載檢測到的冗餘類型将導緻編譯時(shí)錯誤。包含:

解析出來的類型隻能(néng)出現一(yī)次。例如(rú)這(zhè)樣的類型 int|string|INT 或 Countable&Traversable&COUNTABLE 會導緻錯誤。

使用 mixed 會導緻錯誤。

對于聯合類型:

使用了(le) bool 時(shí)就不能(néng)再附帶使用 false 或者 true。

使用了(le) object 時(shí)就不能(néng)再附帶使用 class 類型。

使用了(le) iterable 時(shí),不能(néng)再附帶使用 array 和(hé) Traversable。

對于交集類型:

使用 class-type 以外(wài)的類型會導緻錯誤。

使用 self、parent 或 static 都(dōu)會導緻錯誤。

DNF 類型:

If a more generic type is used, the more restrictive one is redundant.

使用兩個相同的交集類型。

注意: 不過它不能(néng)确保類型最小化,因為(wèi)要(yào)達到這(zhè)樣的效果,還要(yào)加載使用類型的 class。

例如(rú),假設 A 和(hé) B 都(dōu)是一(yī)個類的别名, 而 A|B 仍然是有效的,哪怕它可(kě)以被簡化為(wèi) A 或 B。 同樣的,如(rú)果 B extends A {},那(nà) A|B 仍然是有效的聯合類型,盡管它可(kě)以被簡化為(wèi) 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" 是名稱解析的一(yī)部分)

function foo(): A&B {} // 不允許 ("use" 是名稱解析的一(yī)部分)

class_alias('X', 'Y');

function foo(): X|Y {} // 允許 (運行(xíng)時(shí)才能(néng)知道(dào)重複性)

function foo(): X&Y {} // 允許 (運行(xíng)時(shí)才能(néng)知道(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() {} }

// 沒有實現(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)例程會輸出:

float(3)

示例 #6 返回對象

<?php

class C {}

function getC(): C {

return new C;

}

var_dump(getC());

?>

以上(shàng)例程會輸出:

object(C)#1 (0) {

}

示例 #7 可(kě)為(wèi) null 參數(shù)類型聲明(míng)

<?php

class C {}

function f(?C $c) {

var_dump($c);

}

f(new C);

f(null);

?>

以上(shàng)例程會輸出:

object(C)#1 (0) {

}

NULL

示例 #8 可(kě)為(wèi) null 返回類型聲明(míng)

<?php

function get_item(): ?string {

if (isset($_GET['item'])) {

return $_GET['item'];

} else {

return null;

}

}

?>

嚴格類型 ¶

默認如(rú)果可(kě)能(néng),PHP 會強制轉化不合适的類型為(wèi)想要(yào)的标量類型。 比如(rú),參數(shù)想要(yào) string,傳入的是 int, 則會獲取 string 類型的變量。

可(kě)以按文件開(kāi)啓嚴格模式。 在嚴格模式下(xià),隻能(néng)接受完全匹配的類型,否則會抛出 TypeError。 唯一(yī)的例外(wài)是 int 值也可(kě)以傳入聲明(míng)為(wèi) float 的類型。

警告

通(tōng)過內(nèi)部函數(shù)調用函數(shù)時(shí),不會受 strict_types 聲明(míng)影響。

要(yào)開(kāi)啓嚴格模式,使用 declare 開(kāi)啓 strict_types:

注意:

文件開(kāi)啓嚴格類型後的內(nèi)部調用函數(shù)将應用嚴格類型, 而不是在聲明(míng)函數(shù)的文件內(nèi)開(kāi)啓。 如(rú)果文件沒有聲明(míng)開(kāi)啓嚴格類型,而被調用的函數(shù)所在文件有嚴格類型聲明(míng), 那(nà)将遵循調用者的設置(開(kāi)啓類型強制轉化), 值也會強制轉化。

注意:

隻有為(wèi)标量類型的聲明(míng)開(kāi)啓嚴格類型。

示例 #9 參數(shù)值的嚴格類型

<?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 參數(shù)值的類型強制轉化

<?php

function sum(int $a, int $b) {

return $a + $b;

}

var_dump(sum(1, 2));

// 以下(xià)會強制轉化為(wèi)整型,注意以下(xià)內(nèi)容輸出!

var_dump(sum(1.5, 2.5));

?>

以上(shàng)例程會輸出:

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)例程會輸出:

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>

網站建設開(kāi)發|APP設計開(kāi)發|小程序建設開(kāi)發
下(xià)一(yī)篇:類型轉換
上(shàng)一(yī)篇:Iterable 可(kě)叠代對象