天天看點

《Hack與HHVM權威指南》——1.5.3 屬性值初始化

為了維護類型安全,類型标注過的屬性在初始化時,無論是嚴格模式還是局部模式,類型檢查器會強加一些規則。首要目标就是確定屬性值在沒有初始化為正确類型的值之前,不能被讀取。

對于靜态的屬性值,規則非常簡單:任何不可為空的(non-nullable)的靜态屬性值都必須有一個初始化值。沒有顯式初始值的任何可為空的(nullable)屬性值将會被隐性地初始化為null。

非靜态的屬性值将會有一套更加複雜的規則。類型檢查器将確定絕對不會對一個擁有未被初始化的不可為空的屬性值的對象進行執行個體化。為達到這個目的,任何不可為空、非靜态的屬性值如果沒有初始化值的話,都必須在類的構造函數中進行初始化:

這個代碼将會通過類型檢查器的檢查:屬性$name已經被恰當地初始化了,并且$address也是可為空的,那麼它不需要被初始化。

類型檢查器将會確定在構造函數中的所有代碼分支下,所有的屬性值都被初始化。下面的代碼:

類型檢查器将會報告一個錯誤:

對于類型檢查器的這條規則,另外一個組成部分是,在構造函數所有的屬性被初始化之前,不允許調用任何公共的或者受保護的方法。下面的代碼:

類型檢查器将會抛出一個錯誤(不管怎樣,你都會被允許在$this->name指派之後調用$this->dosomething()方法 ):

在這種情況下,允許調用私有方法,但是你所調用的每個私有方法都會被嚴格檢查,以避免通路到沒有被初始化的屬性值。非私有的方法不能夠通過這種方法進行檢查,因為它們可能在子類之中被覆寫,是以在這種情形下,對非私有方法的調用是非法的。請參考下面的代碼:

類型檢查器将會抛出這個錯誤(再說一次,在$this->name指派後允許調用$th

is->dumpinfo()方法):

在抽象類中聲明的屬性具有規則豁免權。不管怎樣,具體的子類進行初始化的時候都會要求初始化它的祖先類未初始化的屬性值。請看下面的代碼:

類型檢查器将會抛出如下錯誤:

最後,對于本節中的例子,屬性值作為構造函數的一個參數進行初始化,你可以使用構造函數參數更新(詳情請見3.5節的内容)。它避免了公式化的代碼,而且你根本不必對屬性初始化的問題思考什麼事情: