yii2中元件為何能直接使用行為的屬性 - 揭祕不一樣的get函式。

阿北哥ya發表於2017-08-22

上幾篇我們講解了如何為一個元件類配置行為及其執行原理,本篇為大家講解yii2元件是如何做到像訪問自己屬性一樣訪問行為的屬性。

首先要說的是這並不複雜,但是它可以解決你之前的很多疑問,比如為何必須是繼承元件(Component)的類才能使用行為。我們都知道在php中有一個魔術方法__get,我們需要先了解一下它。

先解釋一下__get方法

當訪問不存在或者不能訪問的成員變數時物件會自動呼叫__get()方法.

begin

就是通過這個方法,yii2的Component類訪問到了關聯行為的屬性。

看看檔案 vendor/yiisoft/yii2/base/Component.php line127 __get方法。

public function __get($name) {
    $getter = 'get' . $name;
    if (method_exists($this, $getter)) {
        // read property, e.g. getName()
        return $this->$getter();
    }

    // behavior property
    $this->ensureBehaviors();
    foreach ($this->_behaviors as $behavior) {
        if ($behavior->canGetProperty($name)) {
            return $behavior->$name;
        }
    }
    ...
}複製程式碼

函式首先判斷了 method_exists($this, $getter) 是否存在,如果存在則呼叫,還記得你如何定義AR的關聯方法麼,就是這段程式碼實現的。

接下來我們看重頭戲,首先 Component 執行了自身的 $this->ensureBehaviors(); 上一篇我們學習了這個函式保證了所有相關行為物件都各就各位,然後函式遍歷了所有行為物件。

如果 $behavior->canGetProperty($name) 為真,則返回行為的相關屬性(這個屬性必須是public的),實現下面的結果

$model = new User();

$model->name;
↓
$model->__get('name');
↓ //$behavior->canGetProperty($name)
return $behavior->name;複製程式碼

就是這樣的邏輯。你明白了麼?

canGetProperty

接下來說說 canGetProperty 函式,這是object的一個方法,我們知道Component和Behavior都是它的子類,這個方法主要用於判斷一個屬性是否存在。

因此就是判斷在對應行為物件中屬性是否存在,就像上面的 $behavior 的 name屬性,如果能訪問到自然是好,否則這又是一次輪迴,呼叫__get方法看看getName函式是否存在,如果存在也是可以的,比如下面的行為注入到User類

namespace app\components;

use yii\base\Behavior;

class HelloBehavior extends Behavior {

    public function getName(){
        return "abei20172";
    }
}


// action
$model = new User();
echo $model->name;//abei20172複製程式碼

要注意 canGetProperty 只是判斷屬性是否存在,並不會檢查其範圍是否為 public, private, protected。當然最後只有public才能正確訪問。

如下程式碼

namespace app\components;

use yii\base\Behavior;

class HelloBehavior extends Behavior {
    protected $name = "abei2017";
}


// action
$model = new User();
echo $model->name;複製程式碼

我們會得到一個異常。

protected不能直接訪問
protected不能直接訪問

就這樣

我們通過__get方法實現了行為屬性對元件類的注入,現在你明白為啥能直接訪問了吧?下一篇我們說說行為方法的注入原理。


相關文章