上幾篇咱們講解了如何爲一個組件類配置行爲及其運行原理,本篇爲你們講解yii2組件是如何作到像訪問本身屬性同樣訪問行爲的屬性。php
首先要說的是這並不複雜,可是它能夠解決你以前的不少疑問,好比爲什麼必須是繼承組件(Component)的類才能使用行爲。咱們都知道在php中有一個魔術方法__get,咱們須要先了解一下它。yii2
先解釋一下__get方法app
當訪問不存在或者不能訪問的成員變量時對象會自動調用__get()方法.yii
就是經過這個方法,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的關聯方法麼,就是這段代碼實現的。this
接下來咱們看重頭戲,首先 Component 執行了自身的 $this->ensureBehaviors(); 上一篇咱們學習了這個函數保證了全部相關行爲對象都各就各位,而後函數遍歷了全部行爲對象。spa
若是 $behavior->canGetProperty($name) 爲真,則返回行爲的相關屬性(這個屬性必須是public的),實現下面的結果code
$model = new User(); $model->name; ↓ $model->__get('name'); ↓ //$behavior->canGetProperty($name) return $behavior->name;
就是這樣的邏輯。你明白了麼?component
接下來講說 canGetProperty 函數,這是object的一個方法,咱們知道Component和Behavior都是它的子類,這個方法主要用於判斷一個屬性是否存在。
所以就是判斷在對應行爲對象中屬性是否存在,就像上面的 $behavior 的 name屬性,若是能訪問到天然是好,不然這又是一次輪迴,調用__get方法看看getName函數是否存在,若是存在也是能夠的,好比下面的行爲注入到User類
<?php 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方法實現了行爲屬性對組件類的注入,如今你明白爲啥能直接訪問了吧?下一篇咱們說說行爲方法的注入原理。