Yii2的深入学习--行为Behavior
我们先来看下行为在 Yii2 中的使用,如下内容摘自 Yii2中文文档
行为是 [[yii\base\Behavior]] 或其子类的实例。行为,也称为 mixins,可以无须改变类继承关系即可增强一个已有的 [[yii\base\Component|组件]] 类功能。当行为附加到组件后,它将“注入”它的方法和属性到组件,然后可以像访问组件内定义的方法和属性一样访问它们。此外,行为通过组件能响应被触发的事件,从而自定义或调整组件正常执行的代码。
定义行为
要定义行为,通过继承 [[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 方法定义属性
Tip: 在行为内部可以通过 [[yii\base\Behavior::owner]] 属性访问行为已附加的组件。
处理事件
如果要让行为响应对应组件的事件触发,就应覆写 [[yii\base\Behavior::events()]] 方法,如:
namespace app\components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
// 其它代码
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event)
{
// 处理器方法逻辑
}
}
[[yii\base\Behavior::events()|events()]] 方法返回事件列表和相应的处理器。上例声明了 [[yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE|EVENT_BEFORE_VALIDATE]] 事件和它的处理器 beforeValidate() 。当指定一个事件处理器时,要使用以下格式之一:
- 指向行为类的方法名的字符串,如上例所示;
- 对象或类名和方法名的数组,如
[$object, 'methodName']; - 匿名方法。
处理器的格式如下,其中 $event 指向事件参数。关于事件的更多细节请参考事件:
function ($event) {
}
附加行为
可以静态或动态地附加行为到[[yii\base\Component|组件]]。前者在实践中更常见。
要静态附加行为,覆写行为要附加的组件类的 [[yii\base\Component::behaviors()|behaviors()]] 方法即可。[[yii\base\Component::behaviors()|behaviors()]] 方法应该返回行为配置列表。每个行为配置可以是行为类名也可以是配置数组。如:
namespace app\models;
use yii\db\ActiveRecord;
use app\components\MyBehavior;
class User extends ActiveRecord
{
public function behaviors()
{
return [
// 匿名行为,只有行为类名
MyBehavior::className(),
// 命名行为,只有行为类名
'myBehavior2' => MyBehavior::className(),
// 匿名行为,配置数组
[
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
// 命名行为,配置数组
'myBehavior4' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]
];
}
}
通过指定行为配置数组相应的键可以给行为关联一个名称。这种行为称为命名行为。上例中,有两个命名行为:myBehavior2 和 myBehavior4 。如果行为没有指定名称就是匿名行为。
要动态附加行为,在对应组件里调用 [[yii\base\Component::attachBehavior()]] 方法即可,如:
use app\components\MyBehavior;
// 附加行为对象
$component->attachBehavior('myBehavior1', new MyBehavior);
// 附加行为类
$component->attachBehavior('myBehavior2', MyBehavior::className());
// 附加配置数组
$component->attachBehavior('myBehavior3', [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]);
可以通过 [[yii\base\Component::attachBehaviors()]] 方法一次附加多个行为:
$component->attachBehaviors([
'myBehavior1' => new MyBehavior, // 命名行为
MyBehavior::className(), // 匿名行为
]);
还可以通过配置去附加行为:
[
'as myBehavior2' => MyBehavior::className(),
'as myBehavior3' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
]
使用行为
使用行为,必须像前文描述的一样先把它附加到 [[yii\base\Component|component]] 类或其子类。一旦行为附加到组件,就可以直接使用它。
行为附加到组件后,可以通过组件访问一个行为的公共成员变量或 getter 和 setter 方法定义的属性:
// "prop1" 是定义在行为类的属性
echo $component->prop1;
$component->prop1 = $value;
类似地也可以调用行为的公共方法:
// foo() 是定义在行为类的公共方法
$component->foo();
如你所见,尽管 $component 未定义 prop1 和 foo() ,它们用起来也像组件自己定义的一样。
如果两个行为都定义了一样的属性或方法,并且它们都附加到同一个组件,那么首先附加上的行为在属性或方法被访问时有优先权。
附加行为到组件时的命名行为,可以使用这个名称来访问行为对象,如下所示:
$behavior = $component->getBehavior('myBehavior');
也能获取附加到这个组件的所有行为:
$behaviors = $component->getBehaviors();
移除行为
要移除行为,可以调用 [[yii\base\Component::detachBehavior()]] 方法用行为相关联的名字实现:
$component->detachBehavior('myBehavior1');
也可以移除全部行为:
$component->detachBehaviors();
使用 TimestampBehavior
这个行为支持在 [[yii\db\ActiveRecord|Active Record]] 存储时自动更新它的时间戳属性。
首先,附加这个行为到计划使用该行为的 [[yii\db\ActiveRecord|Active Record]] 类:
namespace app\models\User;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
],
];
}
}
以上指定的行为数组:
- 当记录插入时,行为将当前时间戳赋值给
created_at和updated_at属性; - 当记录更新时,行为将当前时间戳赋值给
updated_at属性。
保存 User 对象,将会发现它的 created_at 和 updated_at 属性自动填充了当前时间戳:
$user = new User;
$user->email = 'test@example.com';
$user->save();
echo $user->created_at; // 显示当前时间戳
[[yii\behaviors\TimestampBehavior|TimestampBehavior]] 行为还提供了一个有用的方法 [[yii\behaviors\TimestampBehavior::touch()|touch()]],这个方法能将当前时间戳赋值给指定属性并保存到数据库:
$user->touch('login_time');
使用 AttributeBehavior
这个行为支持在 [[yii\db\ActiveRecord|Active Record]] 事件触发时自动修改它的属性。
首先,附加这个行为到计划使用该行为的 [[yii\db\ActiveRecord|Active Record]] 类:
namespace app\models\User;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
[
'class' => AttributeBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => 'attribute1',
ActiveRecord::EVENT_BEFORE_UPDATE => 'attribute2',
],
'value' => function ($event) {
return 'some value';
},
],
];
}
}
以上指定的行为数组:
- 当记录插入时,行为将value的返回值给
attribute1属性; - 当记录更新时,行为将value的返回值给
attribute2属性;
与 PHP traits 的比较
尽管行为在 "注入" 属性和方法到主类方面类似于 traits ,它们在很多方面却不相同。如上所述,它们各有利弊。它们更像是互补的而不是相互替代。
行为的优势
行为类像普通类支持继承。另一方面,traits 可以视为 PHP 语言支持的复制粘贴功能,它不支持继承。
行为无须修改组件类就可动态附加到组件或移除。要使用 traits,必须修改使用它的类。
行为是可配置的而 traits 不能。
行为以响应事件来自定义组件的代码执行。
当不同行为附加到同一组件产生命名冲突时,这个冲突通过先附加行为的优先权自动解决。而由不同 traits 引发的命名冲突需要通过手工重命名冲突属性或方法来解决。
traits 的优势
traits 比起行为更高效,因为行为是对象,消耗时间和内存。
IDE 对 traits 更友好,因为它们是语言结构。
Yii2的深入学习--行为Behavior的更多相关文章
- Yii2的深入学习--继承关系
想要了解 Yii2 的话,一定要对 Yii2 中相关类的继承关系有所了解.由于暂时读的代码有限,下面的图中只列出了部分继承关系,之后回跟着源码阅读的越来越多而增加 由上图可以看到 Yii2 中大多数类 ...
- Yii2的深入学习--入口文件
前一段时间,尝试去写一个 php 的简单框架,发现自己还欠缺很多,就暂时停掉了.准备先读完 Yii2 的源码,然后再去看完 laravel 的源码,最后再继续去写这个简单的 php 框架. 之后关于 ...
- yii2源码学习笔记(十一)
Controller控制器类,是所有控制器的基类,用于调用模型和布局. <?php /** * @link http://www.yiiframework.com/ * @copyright C ...
- yii2源码学习笔记(八)
Action是所有控制器的基类,接下来了解一下它的源码.yii2\base\Action.php <?php /** * @link http://www.yiiframework.com/ * ...
- yii2源码学习笔记(六)
Behvaior类,Behavior类是所有事件类的基类: 目录yii2\base\Behavior.php <?php /** * @link http://www.yiiframework. ...
- Yii2的相关学习记录,下载Yii2(一)
原先学习过Yii1的相关知识,虽然也是半懂不懂的,但稍微的结构是了解的.现在利用晚上的时间学习下Yii2的使用,打算建一个后台管理系统,这里记录下,以免自己以后忘记. 目前已看一部分Yii2的权威指南 ...
- Yii2.0源码阅读-behavior的实现原理
Yii2.0中的一个思想就是组件化的思想,所以.大多数的类都直接或间接的继承自yii\base\Component,而组件的三大功能:属性.事件.行为. 行为的目的是为了方便的扩展一个类的功能,而不需 ...
- Yii2基本概念之——行为(Behavior)
使用行为(behavior)可以在不修改现有类的情况下,对类的功能进行扩充.通过将行为绑定到一个类,可以使得类具有行为本身所具有的属性和方法,就好像是类本来就具有的这些属性和功能一样. 好的代码设计, ...
- Yii2的深入学习--事件Event
我们先来看下事件在 Yii2 中的使用,如下内容摘自 Yii2中文文档 事件可以将自定义代码“注入”到现有代码中的特定执行点.附加自定义代码到某个事件,当这个事件被触发时,这些代码就会自动执行.例如, ...
随机推荐
- iOS总结_UI层自我复习总结
UI层复习笔记 在main文件中,UIApplicationMain函数一共做了三件事 根据第三个参数创建了一个应用程序对象 默认写nil,即创建的是UIApplication类型的对象,此对象看成是 ...
- ExtJS 4.2 Date组件扩展:添加清除按钮
ExtJS中除了提供丰富的组件外,我们还可以扩展他的组件. 在这里,我们将在Date日期组件上添加一个[清除]按钮,用于此组件已选中值的清除. 目录 1. Date组件介绍 2. 主要代码说明 3. ...
- CoreCRM 开发实录——开始之新项目的技术选择
2016年11月,接受了一个工作,是对"悟空CRM"进行一些修补.这是一个不错的 CRM,开源,并提供一个 SaaS 的服务.正好微软的 .NET Core 和 ASP.NET C ...
- python 数据类型 -- 元组
元组其实是一种只读列表, 不能增,改, 只可以查询 对于不可变的信息将使用元组:例如数据连接配置 元组的两个方法: index, count >>> r = (1,1,2,3) &g ...
- BPM与 SAP & Oracle EBS集成解决方案分享
一.需求分析 SAP和Oracle EBS都是作为全球顶级的的ERP产 品,得到了众多客户的青睐.然而由于系统庞大.价格昂贵以及定位不同,客户在实施过程中经常会面临以下困惑: 1.SAP如何实现&qu ...
- 小程序用户反馈 - HotApp小程序统计仿微信聊天用户反馈组件,开源
用户反馈是小程序开发必要的一个功能,但是和自己核心业务没关系,主要是产品运营方便收集用户的对产品的反馈.HotApp推出了用户反馈的组件,方便大家直接集成使用 源码下载地址: https://gith ...
- Linux实战教学笔记02:计算机系统硬件核心知识
标签(空格分隔):Linux实战教学笔记-陈思齐 第1章 互联网企业常见服务器介绍 1.1 互联网公司服务器品牌 - DELL(大多数公司,常用) - HP - IBM(百度在用) 浪潮 联想 航天联 ...
- Struts2数据校验
Struts2数据校验 1.常见数据校验方法 表单数据的校验方式: 表单中的数据必须被效验以后才能够被使用,常用的效验方式分为两种: 前台校验:也称之为客户端效验,主要是通过JS编程的方式进行表单数据 ...
- ASP.NET跨平台最佳实践
前言 八年的坚持敌不过领导的固执,最终还是不得不阔别已经成为我第二语言的C#,转战Java阵营.有过短暂的失落和迷茫,但技术转型真的没有想象中那么难.回头审视,其实单从语言本身来看,C#确实比Java ...
- node应用线上部署时锁定包的依赖版本
npm shrinkwrap 我们使用node开发时,经常需要依赖一些模块来完成功能需求,而我们所依赖的模块也必然会依赖其他模块,就这样一级一级的依赖,而且这些依赖模块并不为我们所控制.一个产品或项目 ...