共計 3893 個字符,預計需要花費 10 分鐘才能閱讀完成。
這篇文章給大家介紹 Object 和 Component 的區別是什么,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
由于 Componet 引入了事件、行為,因此,它并非簡單繼承了 Object 的屬性實現方式,而是基于同樣的機制,重載了 __get() __set() 等函數。但從實現機制上來講,是一樣的。這個不影響理解。
前面說過,官方將 Yii 定位于一個基于組件的框架。可見組件這一概念是 Yii 的基礎。如果你有興趣閱讀 Yii 的源代碼或是 API 文檔,你將會發現,Yii 幾乎所有的核心類都派生于(繼承自) yii\base\Component。
在 Yii1.1 時,就已經有了 component 了,那時是 CComponent。Yii2 將 Yii1.1 中的 CComponent 拆分成兩個類:yii\base\Object 和 yii\base\Component。
其中,Object 比較輕量級些,通過 getter 和 setter 定義了類的屬性 (property)。Component 派生自 Object,并支持事件(event) 和行為(behavior)。因此,Component 類具有三個重要的特性:屬性(property)、事件(event)、行為(behavior)。
相信你或多或少了解過,這三個特性是豐富和拓展類功能、改變類行為的重要切入點。因此,Component 在 Yii 中的地位極高。
在提供更多功能、更多便利的同時,Component 由于增加了 event 和 behavior 這兩個特性,在方便開發的同時,也犧牲了一定的效率。如果開發中不需要使用 event 和 behavior 這兩個特性,比如表示一些數據的類。那么,可以不從 Component 繼承,而從 Object 繼承。典型的應用場景就是如果表示用戶輸入的一組數據,那么,使用 Object。而如果需要對對象的行為和能響應處理的事件進行處理,毫無疑問應當采用 Component。從效率來講,Object 更接近原生的 PHP 類,因此,在可能的情況下,應當優先使用 Object。
Object 的配置方法
Yii 提供了一個統一的配置對象的方式。這一方式貫穿整個 Yii。Application 對象的配置就是這種配置方式的體現:
$config = yii\helpers\ArrayHelper::merge(
require(__DIR__ . /../../common/config/main.php),
require(__DIR__ . /../../common/config/main-local.php),
require(__DIR__ . /../config/main.php),
require(__DIR__ . /../config/main-local.php)
);
$application = new yii\web\Application($config);
$config 看著復雜,但本質上就是一個各種配置項的數組。Yii 中就是統一使用數組的方式對對象進行配置,而實現這一切的關鍵就在 yii\base\Object 定義的構造函數中:
public function __construct($config = [])
{
if (!empty($config)) {
Yii::configure($this, $config);
}
$this- init();
}
所有 yii\base\Object 的構建流程是:
構建函數以 $config 數組為參數被自動調用。
構建函數調用 Yii::configure() 對對象進行配置。
在最后,構造函數調用對象的 init() 方法進行初始化。
數組配置對象的秘密在 Yii::configure() 中,但說破了其實也沒有什么神奇的:
public static function configure($object, $properties)
{
foreach ($properties as $name = $value) {
$object- $name = $value;
}
return $object;
}
配置的過程就是遍歷 $config 配置數組,將數組的鍵作為屬性名,以對應的數組元素的值對對象的屬性賦值。因此,實現 Yii 這一統一的配置方式的要點有:
繼承自 yii\base\Object。
為對象屬性提供 setter 方法,以正確處理配置過程。
如果需要重載構造函數,請將 $config 作為該構造函數的最后一個參數,并將該參數傳遞給父構造函數。
重載的構造函數的最后,一定記得調用父構造函數。
如果重載了 yii\base\Object::init() 函數,注意一定要在重載函數的開頭調用父類的 init()。
只要實現了以上要點,就可以使得你編寫的類可以按照 Yii 約定俗成的方式進行配置。這在編寫代碼的過程中,帶來許多便利。
像你這么聰明的,肯定會提出來,如果配置數組的某個配置項,也是一個數組,這怎么辦? 如果某個對象的屬性,也是一個對象,而非一個簡單的數值或字符串時,又怎么辦?
這兩個問題,其實是同質的。如果一個對象的屬性,是另一個對象,就像 Application 里會引入諸多的 Component 一樣,這是很常見的。如后面會看到的 $app- request 中的 request 屬性就是一個對象。那么,在配置 $app 時,必然要配置到這個 reqeust 對象。既然 request 也是一個對象,那么他的配置要是按照 Yii 的規矩來,也就是用一個數組來配置它。因此,上面提到的這兩個問題,其實是同質的。
那么,怎么實現呢? 秘密在于 setter 函數。由于 $app 在進行配置時,最終會調用 Yii::configure() 函數。該函數又不區分配置項是簡單的數值還是數組,就直接使用 $object- $name = $value 完成屬性的賦值。那么,對于對象屬性,其配置值 $value 是一個數組,為了使其正確配置。你需要在其 setter 函數上做出正確的處理方式。Yii 應用 yii\web\Application 就是依靠定義專門的 setter 函數,實現自動處理配置項的。比如,我們在 Yii 的配置文件中,可以看到一個配置項 components,一般情況下,他的內容是這樣的:
components = [
request = [
// !!! insert a secret key in the following (if it is empty) –
// this is required by cookie validation
cookieValidationKey = v7mBbyetv4ls7t8UIqQ2IBO60jY_wf_U ,
],
user = [
identityClass = common\models\User ,
enableAutoLogin = true,
],
log = [
traceLevel = YII_DEBUG ? 3 : 0,
targets = [
[
class = yii\log\FileTarget ,
levels = [error , warning],
],
],
],
errorHandler = [
errorAction = site/error ,
],
],
這是一個典型嵌套配置數組。那么 Yii 是如何把他們配置好的呢? 聰明的你肯定想到了,Yii 一定是定義了一個名為 setComponents 的 setter 函數。當然,Yii 并未將該函數放在 yii\web\Application 里,而是放在父類 yii\di\ServiceLocator 里面。至于 ServiceLocator 是何方神圣,在后面 服務定位器(Service Locator) 部分會講到,這里你只需要知道它是 Application 的父類,提供 components 屬性的 setter 方法就可以了:
public function setComponents($components)
{
foreach ($components as $id = $component) {
$this- set($id, $component);
}
}
這里有個成員函數,$this- set(),他是服務定位器用來注冊服務的方法。我們暫時不講這個東西,留待 服務定位器(Service Locator) 部分再講?,F在只要知道這個函數把配置文件中的 components 配置項搞定就可以了。
從 yii\base\Object::__construct() 來看,對于所有 Object,包括 Component 的屬性,都經歷這么 4 個階段:
預初始化階段。這是最開始的階段,就是在構造函數 __construct() 的開頭可以設置 property 的默認值。
對象配置階段。也就是前面提到構造函數調用 Yii::configure($this, $config) 階段。這一階段可以覆蓋前一階段設置的 property 的默認值,并補充沒有默認值的參數,也就是必備參數。$config 通常由外部代碼傳入或者通過配置文件傳入。
后初始化階段。也就是構造函數調用 init() 成員函數。通過在 init() 寫入代碼,可以對配置階段設置的值進行檢查,并規范類的 property。
類方法調用階段。前面三個階段是不可分的,由類的構造函數一口氣調用的。也就是說一個類一但實例化,那么就至少經歷了前三個階段。此時,該對象的狀態是確定且可靠的,不存在不確定的 property。所有的屬性要么是默認值,要么是傳入的配置值,如果傳入的配置有誤或者沖突,那么也經過了檢查和規范。也就是說,你就放心用吧。
關于 Object 和 Component 的區別是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。