当前位置:首页 > PHP教程 > php高级应用 > 列表

PHP的Yii框架中行为的定义与绑定方法讲解

发布:smiling 来源: PHP粉丝网  添加日期:2019-11-14 15:43:59 浏览: 评论:0 

定义行为

要定义行为,通过继承 yii\base\Behavior 或其子类来建立一个类。如:

  1. namespace app\components; 
  2.  
  3.   
  4.  
  5. use yii\base\Behavior; 
  6.  
  7.   
  8.  
  9. class MyBehavior extends Behavior 
  10.  
  11. { 
  12.  
  13.   public $prop1; 
  14.  
  15.   
  16.  
  17.   private $_prop2; 
  18.  
  19.   
  20.  
  21.   public function getProp2() 
  22.  
  23.   { 
  24.  
  25.     return $this->_prop2; 
  26.  
  27.   }  
  28.  
  29.   public function setProp2($value) 
  30.  
  31.   { 
  32.  
  33.     $this->_prop2 = $value; 
  34.  
  35.   } 
  36.  
  37.   public function foo() 
  38.  
  39.   { 
  40.  
  41.     // ... 
  42.  
  43.   } 
  44.  
  45. } 

以上代码定义了行为类 app\components\MyBehavior 并为要附加行为的组件提供了两个属性 prop1 、 prop2 和一个方法 foo()。注意属性 prop2 是通过 getter getProp2() 和 setter setProp2() 定义的。能这样用是因为 yii\base\Object 是 yii\base\Behavior 的祖先类,此祖先类支持用 getter 和 setter 方法定义属性

提示:在行为内部可以通过 yii\base\Behavior::owner 属性访问行为已附加的组件。

静态方法绑定行为

静态绑定行为,只需要重载 yii\base\Component::behaviors() 就可以了。 这个方法用于描述类所具有的行为。如何描述呢? 使用配置来描述,可以是Behavior类名,也可以是Behavior类的配置数组:

  1. namespace app\models; 
  2.  
  3.   
  4.  
  5. use yii\db\ActiveRecord; 
  6.  
  7. use app\Components\MyBehavior; 
  8.  
  9.   
  10.  
  11. class User extends ActiveRecord 
  12.  
  13. { 
  14.  
  15.   public function behaviors() 
  16.  
  17.   { 
  18.  
  19.     return [ 
  20.  
  21.       // 匿名的行为,仅直接给出行为的类名称 
  22.  
  23.       MyBehavior::className(), 
  24.  
  25.   
  26.  
  27.       // 名为myBehavior2的行为,也是仅给出行为的类名称 
  28.  
  29.       'myBehavior2' => MyBehavior::className(), 
  30.  
  31.   
  32.  
  33.       // 匿名行为,给出了MyBehavior类的配置数组 
  34.  
  35.       [ 
  36.  
  37.         'class' => MyBehavior::className(), 
  38.  
  39.         'prop1' => 'value1', 
  40.  
  41.         'prop3' => 'value3', 
  42.  
  43.       ], 
  44.  
  45.   
  46.  
  47.       // 名为myBehavior4的行为,也是给出了MyBehavior类的配置数组 
  48.  
  49.       'myBehavior4' => [ 
  50.  
  51.         'class' => MyBehavior::className(), 
  52. //phpfensi.com 
  53.         'prop1' => 'value1', 
  54.  
  55.         'prop3' => 'value3', 
  56.  
  57.       ] 
  58.  
  59.     ]; 
  60.  
  61.   } 
  62.  
  63. } 

还有一个静态的绑定办法,就是通过配置文件来绑定:

  1. [ 
  2.  
  3.   'as myBehavior2' => MyBehavior::className(), 
  4.  
  5.   'as myBehavior3' => [ 
  6.  
  7.     'class' => MyBehavior::className(), 
  8.  
  9.     'prop1' => 'value1', 
  10.  
  11.     'prop3' => 'value3', 
  12.  
  13.   ], 
  14.  
  15. ] 

动态方法绑定行为

动态绑定行为,需要调用 yii\base\Compoent::attachBehaviors():

  1. $Component->attachBehaviors([ 
  2.  
  3.   'myBehavior1' => new MyBehavior, // 这是一个命名行为 
  4.  
  5.   MyBehavior::className(),     // 这是一个匿名行为 
  6.  
  7. ]); 

这个方法接受一个数组参数,参数的含义与上面静态绑定行为是一样一样的。

在上面的这些例子中,以数组的键作为行为的命名,而对于没有提供键名的行为,就是匿名行为。

对于命名的行为,可以调用 yii\base\Component::getBehavior() 来取得这个绑定好的行为:

$behavior = $Component->getBehavior('myBehavior2');

对于匿名的行为,则没有办法直接引用了。但是,可以获取所有的绑定好的行为:

$behaviors = $Component->getBehaviors();

绑定的内部原理

只是重载一个 yii\base\Component::behaviors() 就可以这么神奇地使用行为了? 这只是冰山的一角,实际上关系到绑定的过程,有关的方面有:

  1. yii\base\Component::behaviors() 
  2.  
  3. yii\base\Component::ensureBehaviors() 
  4.  
  5. yii\base\Component::attachBehaviorInternal() 
  6.  
  7. yii\base\Behavior::attach() 

4个方法中,Behavior只占其一,更多的代码,是在Component中完成的。

yii\base\Component::behaviors() 上面讲静态方法绑定行为时已经提到了,就是返回一个数组用于描述行为。 那么 yii\base\Component::ensuerBehaviors() 呢?

这个方法会在Component的诸多地方调用 __get() __set() __isset() __unset() __call() canGetProperty() hasMethod() hasEventHandlers() on() off() 等用到,看到这么多是不是头疼?一点都不复杂,一句话,只要涉及到类的属性、方法、事件这个函数都会被调用到。

这么众星拱月,被诸多凡人所需要的 ensureBehaviors() 究竟是何许人也? 就像名字所表明的,他的作用在于“ensure” 。其实只是确保 behaviors() 中所描述的行为已经进行了绑定而已:

  1. public function ensureBehaviors() 
  2.  
  3. { 
  4.  
  5.   // 为null表示尚未绑定 
  6.  
  7.   // 多说一句,为空数组表示没有绑定任何行为 
  8.  
  9.   if ($this->_behaviors === null) { 
  10.  
  11.     $this->_behaviors = []; 
  12.  
  13.     // 遍历 $this->behaviors() 返回的数组,并绑定 
  14.  
  15.     foreach ($this->behaviors() as $name => $behavior) { 
  16.  
  17.       $this->attachBehaviorInternal($name, $behavior); 
  18.  
  19.     } 
  20.  
  21.   } 
  22.  
  23. } 

这个方法主要是对子类用的, yii\base\Compoent 没有任何预先注入的行为,所以,这个调用没有用。 但是对于子类,你可能重载了 yii\base\Compoent::behaviros() 来预先注入一些行为。 那么,这个函数会将这些行为先注入进来。

从上面的代码中,自然就看到了接下来要说的第三个东东, yii\base\Component\attachBehaviorInternal():

  1. private function attachBehaviorInternal($name, $behavior) 
  2.  
  3. { 
  4.  
  5.   // 不是 Behavior 实例,说是只是类名、配置数组,那么就创建出来吧 
  6.  
  7.   if (!($behavior instanceof Behavior)) { 
  8.  
  9.     $behavior = Yii::createObject($behavior); 
  10.  
  11.   } 
  12.   
  13.   // 匿名行为 
  14.  
  15.   if (is_int($name)) { 
  16.  
  17.     $behavior->attach($this); 
  18.  
  19.     $this->_behaviors[] = $behavior; 
  20.   
  21.   // 命名行为 
  22.  
  23.   } else { 
  24.   
  25.     // 已经有一个同名的行为,要先解除,再将新的行为绑定上去。 
  26.  
  27.     if (isset($this->_behaviors[$name])) { 
  28.  
  29.       $this->_behaviors[$name]->detach(); 
  30.  
  31.     } 
  32.  
  33.     $behavior->attach($this); 
  34.  
  35.     $this->_behaviors[$name] = $behavior; 
  36.  
  37.   } 
  38.  
  39.   return $behavior; 
  40.  
  41. } 

首先要注意到,这是一个private成员。其实在Yii中,所有后缀为 *Internal 的方法,都是私有的。 这个方法干了这么几件事:

如果 $behavior 参数并非是一个 Behavior 实例,就以之为参数,用 Yii::createObject() 创建出来。

如果以匿名行为的形式绑定行为,那么直接将行为附加在这个类上。

如果是命名行为,先看看是否有同名的行为已经绑定在这个类上,如果有,用后来的行为取代之前的行为。

在 yii\base\Component::attachBehaviorInternal() 中, 以 $this 为参数调用了 yii\base\Behavior::attach() 。 从而,引出了跟绑定相关的最后一个家伙 yii\base\Behavior::attach() , 这也是前面我们讲行为的要素时没讲完的。先看看代码:

  1. public function attach($owner) 
  2.  
  3. { 
  4.  
  5.   $this->owner = $owner; 
  6.  
  7.   foreach ($this->events() as $event => $handler) { 
  8.  
  9.     $owner->on($event, is_string($handler) ? [$this, $handler] : 
  10.  
  11.       $handler); 
  12.  
  13.   } 
  14.  
  15. } 

上面的代码干了两件事:

设置好行为的 $owner,使得行为可以访问、操作所依附的对象

遍历行为中的 events() 返回的数组,将准备响应的事件,通过所依附类的 on() 绑定到类上

总结:

说了这么多,关于绑定,做个小结:

绑定的动作从Component发起;

静态绑定通过重载 yii\base\Componet::behaviors() 实现;

动态绑定通过调用 yii\base\Component::attachBehaviors() 实现;

行为还可以通过为 Component 配置 as 配置项进行绑定;

行为有匿名行为和命名行为之分,区别在于绑定时是否给出命名。 命名行为可以通过其命名进行标识,从而有针对性地进行解除等操作;

绑定过程中,后绑定的行为会取代已经绑定的同名行为;

绑定的意义有两点,一是为行为设置 $owner 。二是将行为中拟响应的事件的handler绑定到类中去。

Tags: Yii框架 绑定方法

分享到: