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)

相关推荐

  • 深入浅析yii2-gii自定义模板的方法

    前言: Yii 是什么 Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序.名字 Yii (读作 `易`)在中文里有 "极致简单与不断演变" 两重含义,也可看作 **Yes It Is**! 的缩写. Yii 最适合做什么? Yii 是一个通用的 Web 编程框架,即可以用于开发各种基于 PHP 的 Web 应用.因为基于组件的框架结构和设计精巧的缓存支持,Yii 特别适合开发大型应用,如门户网站.论坛.内容管理系统(CMS).电子商务项目和 RESTf

  • Yii-自定义删除确认弹框(zyd)jquery实现代码

    1.链接 复制代码 代码如下: <?php echo CHtml::link(Yii::t('cmp','Delete'),'javascript:',array('class'=>'c_06c','onclick'=>'return art_del_confirm("/company/msglog/delete/id/'.$data->zml_id.'","你确定要删除这条消息吗?")'))?> 2.jq 复制代码 代码如下: <

  • Yii调试SQL的常用方法

    Yii调试SQL主要有以下方法: 一.系统自带调试: 首先index.php开启调试模式: // remove the following lines when in production mode defined('YII_DEBUG') or define('YII_DEBUG',true); // specify how many levels of call stack should be shown in each log message defined('YII_TRACE_LEVE

  • Yii2.0预定义的别名功能小结

    本文实例讲述了Yii2.0预定义别名.分享给大家供大家参考,具体如下: 这里总结一下,默认预定义别名一共有12个,其中路径别名11个,URL别名只有 @web 1个: @yii 表示Yii框架所在的目录,也是 yii\BaseYii 类文件所在的位置; @app 表示正在运行的应用的根目录,一般是 digpage.com/frontend ; @vendor 表示Composer第三方库所在目录,一般是 @app/vendor 或 @app/../vendor ; @bower 表示Bower第

  • 从零开始学YII2框架(一)通过Composer安装Yii2框架

    最近在学习PHP,着手找一个能快速上手的框架来学习.一开始看兄弟连视频时候讲师推荐ThinkPHP.于是我选择了ThinkPHP来尝试,这个框架的上手难度系数不大,能快速开发一款应用.适合小型的企业应用.因为是国人开发的,中文支持比较好.有比较全面的文档,官网社区也比较活跃.因为我接触的项目都是用Oracle数据库的,所以我想找一款对Oracle支持比较好的PHP框架,但是ThinkPHP框架对Oracle的支持实在是不好.所以我换了Yii框架来试试对Oracle的支持程度. Yii框架现在稳定

  • Yii操作数据库的3种方法

    一.执行原生太SQL的PDO方式. 复制代码 代码如下: $sql = "";//原生态sql语句 xx::model()->dbConnection->createCommand($sql)->execute(); 二.Active Record方式 (1)New 方式 复制代码 代码如下: $post=new Post; $post->title='sample post'; $post->content='post body content'; $p

  • yii2中的rules 自定义验证规则详解

    yii2的一个强大之处之一就是他的Form组件,既方便又安全.有些小伙伴感觉用yii一段时间了,好嘛,除了比tp"难懂"好像啥都没有. 领导安排搞一个注册的功能,这家伙刷刷刷的又是百度啥啥啥好的表单样式,又是百度啥啥啥validate验证,真替这家伙捏把汗. 当然啦,废话说在前头,咱们的重点喃,是要利用ActiveForm,然后怎么去实现自定义验证规则. 先来说说场景: 条件:①.有两个字段分别是A和B ②.A有两个值分别是1和2 需求是:当用户选择的A的值等于1的时候,B的值必须填写

  • 解析yii数据库的增删查改

    1. 存取数据库方法存储第一种存表时候用到例子: 复制代码 代码如下: $post=new Post;$post->title='samplepost';$post->content='content for thesample post';$post->createTime=time();/$post->createTime=newCDbexpression_r('NOW()');$post->save();$user_field_data= new user_field_

  • Yii2使用Bootbox插件实现自定义弹窗

    本次尝试了一个新的小插件"bootbox". Yii2中使用了Bootstarp,让界面更美观,可是美中不足的是,在Gridview表格的Action里,删除功能的弹窗实在有点与Bootstrap违和,网上找到了一种解决方案,分享下使用此插件的过程. Bootbox.js,是一个小型的JavaScript库用来创建简单的可编程对话框,基于Bootstrap的Modal(模态框)来创建. 官方说明 http://bootboxjs.com/v3.x/index.html Bootbox.

  • Yii入门教程之目录结构、入口文件及路由设置

    项目名称从"FantaCMS"修改成为"testyii"------ 俗! 1,项目目录结构分析 2,Yii入口文件分析 在Yii启动项目时,传递了项目主配置文件数组,那么Yii会在整个应用中绑定一个全局的Yii对象并且可以通过如下方法来调用该对象:Yii::app() Yii系统把配置文件中的数组值,通过键值对的形式绑定到了该对象上,例如在配置文件中我们配置了: 'name'=>'My Web Application', 那么我们在项目的任何一个地方通过该对

  • yii2.0之GridView自定义按钮和链接用法

    本文实例讲述了yii2.0之GridView自定义按钮和链接用法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: <?= GridView::widget([         'dataProvider' => $dataProvider,         //'filterModel' => $searchModel,         'columns' => [             ['class' => 'yii\grid\SerialColumn'

  • PHP YII框架开发小技巧之模型(models)中rules自定义验证规则

    YII的models中的rules部分是一些表单的验证规则,对于表单验证十分有用,在相应的视图(views)里面添加了表单,在表单被提交之前程序都会自动先来这里面的规则里验证,只有通过对其有效的限制规则后才能被提交,可以很有效地保证表单安全和信息的有效性.还是给大家具体说明一下: 以下是视图(views)部分的简单代码: <?php $form=$this->beginWidget('CActiveForm', array( 'id'=>'tag-form', 'enableAjaxVa

随机推荐