上幾篇我們講解了如何為一個元件類配置行為及其執行原理,本篇為大家講解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;複製程式碼
我們會得到一個異常。
就這樣
我們通過__get方法實現了行為屬性對元件類的注入,現在你明白為啥能直接訪問了吧?下一篇我們說說行為方法的注入原理。