网络编程
位置:首页>> 网络编程>> php编程>> PHP的Yii框架中行为的定义与绑定方法讲解

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

作者:goldensun  发布时间:2023-07-21 20:42:33 

标签:PHP,Yii

定义行为

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


namespace app\components;

use yii\base\Behavior;

class MyBehavior extends Behavior
{
 public $prop1;

 private $_prop2;

 public function getProp2()
 {
   return $this->_prop2;
 }

 public function setProp2($value)
 {
   $this->_prop2 = $value;
 }

 public function foo()
 {
   // ...
 }
}

以上代码定义了行为类 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类的配置数组:


namespace app\models;

use yii\db\ActiveRecord;
use app\Components\MyBehavior;

class User extends ActiveRecord
{
 public function behaviors()
 {
   return [
     // 匿名的行为,仅直接给出行为的类名称
     MyBehavior::className(),

     // 名为myBehavior2的行为,也是仅给出行为的类名称
     'myBehavior2' => MyBehavior::className(),

     // 匿名行为,给出了MyBehavior类的配置数组
     [
       'class' => MyBehavior::className(),
       'prop1' => 'value1',
       'prop3' => 'value3',
     ],

     // 名为myBehavior4的行为,也是给出了MyBehavior类的配置数组
     'myBehavior4' => [
       'class' => MyBehavior::className(),
       'prop1' => 'value1',
       'prop3' => 'value3',
     ]
   ];
 }
}

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


[
 'as myBehavior2' => MyBehavior::className(),

 'as myBehavior3' => [
   'class' => MyBehavior::className(),
   'prop1' => 'value1',
   'prop3' => 'value3',
 ],
]

动态方法绑定行为

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


$Component->attachBehaviors([
 'myBehavior1' => new MyBehavior, // 这是一个命名行为
 MyBehavior::className(),     // 这是一个匿名行为
]);

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

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

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


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

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


$behaviors = $Component->getBehaviors();

绑定的内部原理

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


yii\base\Component::behaviors()
yii\base\Component::ensureBehaviors()
yii\base\Component::attachBehaviorInternal()
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() 中所描述的行为已经进行了绑定而已:


public function ensureBehaviors()
{
 // 为null表示尚未绑定
 // 多说一句,为空数组表示没有绑定任何行为
 if ($this->_behaviors === null) {
   $this->_behaviors = [];

   // 遍历 $this->behaviors() 返回的数组,并绑定
   foreach ($this->behaviors() as $name => $behavior) {
     $this->attachBehaviorInternal($name, $behavior);
   }
 }
}

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

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


private function attachBehaviorInternal($name, $behavior)
{
 // 不是 Behavior 实例,说是只是类名、配置数组,那么就创建出来吧
 if (!($behavior instanceof Behavior)) {
   $behavior = Yii::createObject($behavior);
 }

 // 匿名行为
 if (is_int($name)) {
   $behavior->attach($this);
   $this->_behaviors[] = $behavior;

 // 命名行为
 } else {

   // 已经有一个同名的行为,要先解除,再将新的行为绑定上去。
   if (isset($this->_behaviors[$name])) {
     $this->_behaviors[$name]->detach();
   }
   $behavior->attach($this);
   $this->_behaviors[$name] = $behavior;
 }
 return $behavior;
}

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

如果 $behavior 参数并非是一个 Behavior 实例,就以之为参数,用 Yii::createObject() 创建出来。
如果以匿名行为的形式绑定行为,那么直接将行为附加在这个类上。
如果是命名行为,先看看是否有同名的行为已经绑定在这个类上,如果有,用后来的行为取代之前的行为。
在 yii\base\Component::attachBehaviorInternal() 中, 以 $this 为参数调用了 yii\base\Behavior::attach() 。 从而,引出了跟绑定相关的最后一个家伙 yii\base\Behavior::attach() , 这也是前面我们讲行为的要素时没讲完的。先看看代码:


public function attach($owner)
{
 $this->owner = $owner;
 foreach ($this->events() as $event => $handler) {
   $owner->on($event, is_string($handler) ? [$this, $handler] :
     $handler);
 }
}

上面的代码干了两件事:

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

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

总结

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

  • 绑定的动作从Component发起;

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

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

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

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

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

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

0
投稿

猜你喜欢

  • 于是我登陆主机的管理面板,重启了网站服务,ldb文件就消失了,网站打开也正常了,但过了数小时后,网站又再次出现以上情况,此种情况持续了好一段
  • 运行代码框<html><META HTTP-EQUIV="Content-Type" content=
  • 那天突然的一个灵感,是针对防盗链的。正常上传的文件,若被人盗链则增加了自己服务器的负担,上次164.cc就因此被挂。然后想想对策,目前各类防
  • 在Vista IIS 7 中用 vs2005 调试 Web 项目核心是要解决以下几个问题:1、Vista 自身在安全性方面的User Acc
  • 自己从工艺品设计到平面设计到网络设计,虽然设计原则不离其宗,但经验下来的心得告诉自己,设计媒介的变化带来很多媒介自身的特殊性,下面总结下网站
  • 写入:1:把gif图像文件读入内存(一个变量strTemp)。2:写入数据库。Dim binTmp() As 
  • CSS命名规范一.文件命名规范全局样式:global.css;框架布局:layout.css;字体样式:font.css;链接样式:link
  • 1.1.1 摘要 如果说要对数据库进行优化,我们主要可以通过以下五种方法,对数据库系统进行优化。 1. 计算机硬件调优 2. 应用程序调优
  • 在微软的ASP编程体系中,ADO对象的建立,使得从网页访问数据库成为一件易事,特别是ADO的Recordset对象使得控制数据的输出显示更为
  • 要开发一个基于数据库的应用系统,其中最关键的一步就是整个系统所依据的数据库的建模设计,从逻辑的到物理的,一个环节疏于设计,整个的应用系统便似
  • 每次在操作数据库的时候最烦的就是根据表单提交的内容写sql语句,特别是字段比较多的时候很麻烦,动不动就容易写错。所以我就写了下面的生成sql
  • //1、运行到C盘根目录 //2、输入:SET ORACLE_SID = 你的SID名称 3、输入:sqlplus/nolog 4、输入:c
  • 1 , javascript字符集:javascript采用的是Unicode字符集编码。为什么要采用这个编码呢?原因很简单,16位的Uni
  • SQL Server数据库查询速度慢的原因有很多,常见的有以下几种:1、没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷)
  • 一个很棒的 blog 文章,是 PPK 两年前写的,文章中解释了 contains() 和 compareDocumentPosition(
  •        多表操作 在一个数据库中,可能存在多个表,这些表都是相互关联的。我
  • 有使用过VS2005开发工具的朋友或者其他语句如js中都有Try catch 语句块,那么在mysql中是否能有SQLserver的@@er
  • SQL Server 2000安装问题集锦1、先把SQL Server卸载(卸载不掉也没有关系,继续下面的操作)2、把Microsoft S
  • 从MySQL 5.0.2开始,通过mysql_stmt_attr_set() C API函数实现了服务器端光标。服务器端光标允许在服务器端生
  • 小贤是一条可爱的小狗(Dog), 它的叫声很好听(wow), 每次看到主人的时候就会乖乖叫一声(yelp).从这段描述可以得到以下对象:fu
手机版 网络编程 asp之家 www.aspxhome.com