溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PHP 7.4中的類型屬性介紹

發(fā)布時間:2020-06-21 16:30:44 來源:億速云 閱讀:170 作者:鴿子 欄目:編程語言

在PHP 7.4中添加了類型屬性,并對PHP的類型系統(tǒng)進(jìn)行了重大改進(jìn)。這些更改是完全可選的,并且不破壞以前的版本。

在這篇文章中,我們將深入了解這個特性,但首先讓我們總結(jié)最重要的幾點:

● 它們自PHP 7.4起可用

● 它們只在類中可用,并且需要訪問修飾符:public、protected或private;或var.

● 除了void和callable之外,所有類型都是允許的

他們的實際情況是這樣的:

class Foo
{
    public int $a;
    public ?string $b = 'foo';
    private Foo $prop;
    protected static string $static = 'default';
}

#未初始化

在查看有趣的內(nèi)容之前,首先要討論類型屬性的一個重要方面。

不管你第一眼看到的是什么,下面的代碼是有效的:

class Foo
{
    public int $bar;
}
$foo = new Foo;

即使$bar的值不是一個整數(shù)后,使一個對象Foo, PHP只會拋出一個錯誤時,$bar被訪問:

var_dump($foo->bar);
Fatal error: Uncaught Error: Typed property Foo::$bar 
must not be accessed before initialization

從錯誤消息中可以看到,有一種新的“變量狀態(tài)”:未初始化。

如果$bar沒有類型,則其值將為null。但是類型可以為空,因此無法確定是否設(shè)置了類型為空的屬性,或者只是將其忘記了。這就是為什么添加了“uninitialized(未初始化)”的原因。

關(guān)于未初始化,要記住四件事:

● 無法讀取未初始化的屬性,這樣做將導(dǎo)致致命錯誤。

● 因為在訪問屬性時會檢查未初始化狀態(tài),所以可以使用未初始化的屬性創(chuàng)建對象,即使其類型不可為空。

● 您可以先寫入未初始化的屬性,然后再讀取它。

● 在類型屬性上使用unset將使其未初始化,而取消對非類型化屬性的設(shè)置將使其為null。

特別要注意,下面的代碼是有效的,其中在構(gòu)造對象之后設(shè)置了非初始化的、不可空的屬性

class Foo
{
    public int $a;
}
$foo = new Foo;
$foo->a = 1;

雖然僅在讀取屬性值時才檢查未初始化狀態(tài),但在寫入屬性值時進(jìn)行類型驗證。這意味著您可以確保任何無效類型都不會以屬性值的形式結(jié)束。

#默認(rèn)值和構(gòu)造函數(shù)

讓我們仔細(xì)看看如何初始化鍵入的值。對于標(biāo)量類型,可以提供一個默認(rèn)值:

class Foo
{
    public int $bar = 4;
    
    public ?string $baz = null;
    
    public array $list = [1, 2, 3];
}

注意,如果類型實際上是空的,則只能使用null作為默認(rèn)值。這似乎是顯而易見的,但是有些舊的行為帶有參數(shù)默認(rèn)值,其中允許以下操作:

function passNull(int $i = null)
{ /* … */ }
passNull(null);

幸運的是,類型屬性不允許這種令人困惑的行為。

另請注意,對象或類類型不可能有默認(rèn)值。您應(yīng)該使用構(gòu)造函數(shù)來設(shè)置它們的默認(rèn)值。

初始化類型化值的明顯地方當(dāng)然是構(gòu)造函數(shù):

class Foo{
    private int $a;
    public function __construct(int $a)
    {
        $this->a = $a;
    }
}

但也請記住我前面提到的:在構(gòu)造函數(shù)外部寫入未初始化的屬性是有效的。只要沒有從屬性中讀取任何內(nèi)容,就不會執(zhí)行未初始化檢查。

#類型的類型

那么究竟什么可以輸入,如何輸入呢?我已經(jīng)提到類型化屬性只在類中有效(目前),它們需要一個訪問修飾符或var關(guān)鍵字在它們前面。

對于可用類型,除了void和callable之外,幾乎所有類型都可以使用。

因為void意味著沒有值,所以不能將其用于鍵入值是有意義的。 callable稍微有點差別。

可見,PHP中的“ callable” 可以這樣寫:

但也請記住我前面提到的:在構(gòu)造函數(shù)外部寫入未初始化的屬性是有效的。只要沒有從屬性中讀取任何內(nèi)容,就不會執(zhí)行未初始化檢查。

看,一個“callable”在PHP可以這樣寫:

$callable = [$this, 'method'];

假設(shè)您有以下(無效)代碼:

class Foo
{
    public callable $callable;
    
    public function __construct(callable $callable)
    { /* … */ }
}
class Bar
{
    public Foo $foo;
    
    public function __construct()
    {
        $this->foo = new Foo([$this, 'method'])
    }
    
    private function method()
    { /* … */ }
}
$bar = new Bar;
($bar->foo->callable)();

在本例中,$callable引用私有Bar::方法,但是在Foo的上下文中被調(diào)用。由于這個問題,決定不添加callable的支持。

不過,這沒什么大不了的,因為Closure是一個有效類型,它將記住構(gòu)造它的$this上下文。

順便說一句,這是所有可用類型的列表:

● bool

● int

● float

● string

● array

● iterable

● object

● ? (nullable)

● self & parent

● Classes & interfaces

#強制類型和嚴(yán)格類型

PHP是我們喜歡和討厭的一種動態(tài)語言,它將盡可能地強制轉(zhuǎn)換類型。假設(shè)您在期望整數(shù)的地方傳遞了一個字符串,PHP將嘗試自動轉(zhuǎn)換該字符串:

function coerce(int $i)
{ /* … */ }
coerce('1'); // 1

同樣的原則也適用于類型屬性。

下面的代碼是有效的,并將“1”轉(zhuǎn)換為1。

class Bar
{
    public int $i;
}
$bar = new Bar;
$bar->i = '1'; // 1

如果您不喜歡這種行為,可以通過聲明嚴(yán)格類型來禁用它:

declare(strict_types=1);
$bar = new Bar;
$bar->i = '1'; // 1
Fatal error: Uncaught TypeError: 
Typed property Bar::$i must be int, string used

#類型差異和繼承

即使PHP 7.4引入了改進(jìn)的類型差異,但類型屬性仍然不變。

這意味著以下內(nèi)容無效:

class A {}
class B extends A {}
class Foo
{
    public A $prop;
}
class Bar extends Foo
{
    public B $prop;
}
Fatal error: Type of Bar::$prop must be A (as in class Foo)

如果上面的示例似乎并不重要,則應(yīng)查看以下內(nèi)容:

class Foo
{
    public self $prop;
}
class Bar extends Foo
{
    public self $prop;
}

在運行代碼之前,PHP將在幕后用它引用的具體類替換self。

這意味著在本例中會拋出相同的錯誤。處理它的唯一方法,是執(zhí)行以下操作:

class Foo
{
    public Foo $prop;
}
class Bar extends Foo
{
    public Foo $prop;
}

說到繼承,您可能會發(fā)現(xiàn)很難找到任何好的用例來覆蓋繼承屬性的類型。

雖然我同意這種觀點,但值得注意的是,可以更改繼承屬性的類型,但前提是訪問修飾符也從private更改為protected或public。

以下代碼有效:

class Foo{
    private int $prop;
}
class Bar extends Foo
{
    public string $prop;
}

但是,不允許將類型從可為空的類型更改為不可為空或反向的類型。

class Foo
{
    public int $a;
    public ?int $b;
}
class Bar extends Foo
{
    public ?int $a;
    public int $b;
}
Fatal error: Type of Bar::$a must be int (as in class Foo)

以上就是PHP 7.4中的類型屬性(Typed Properties)的詳細(xì)內(nèi)容,更多請關(guān)注億速云其它相關(guān)文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI