做自(zì)由與創造的先行者

類型聲明(míng)

PHP中文(wén)手冊

<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)發
下(xià)一篇:類型轉換
上(shàng)一篇:Iterable 可叠代對(duì)象