这多是你们最疑问的地方,到底有和不一样。php
进入咱们本身的解释以前,我先把yii2官方的说法粘贴一份过来,这是一个咱们在选择用行为仍是trait的一个标准。html
尽管行为在 "注入" 属性和方法方面相似于 trait ,它们在不少方面却不相同。如上所述,它们各有利弊。它们更像是互补的而不是相互替代。yii2
行为类像普通类支持继承。另外一方面,trait 能够视为 PHP 语言支持的复制粘贴功能,它不支持继承。app
行为无须修改组件类就可动态附加到组件或移除。要使用 trait,必须修改使用它的类。yii
行为是可配置的而 trait 不能。函数
行为以响应事件来自定义组件的代码执行。spa
当不一样行为附加到同一组件产生命名冲突时,这个冲突经过先附加行为的优先权自动解决。而由不一样 trait 引起的命名冲突须要经过手工重命名冲突属性或方法来解决。code
traits 比起行为更高效,由于行为是对象,消耗时间和内存。component
IDE 对 trait 更友好,由于它们是语言结构。cdn
行为只能服务于组件类,而 trait 没有这个限制。
经过上面的说明,总结来讲就一条:用行为、用行为、用行为。
-------------------我是分割线------------------------
虽然咱们已经会了行为,官方也说你就用行为就好了。可是咱们仍是有必要了解下traits,它究竟是什么?
首先要说的是traits的目的是解决类只能单继承的问题,行为也是这个目的,咱们在第一篇前导课 - 什么是行为?就已经分析了 。
有一点很重要,就是trait不能被实例化。
咱们来举一个 trait 的例子,让你知道什么是trait
trait Mouse {
public $name = '鼠标';
public function click() {
echo "鼠标点击了一下";
}
}
class Computer {
public function sayName(){
echo "我是一台电脑";
}
}
class Macbook extends Computer {
use Mouse;
public function say(){
echo "我是一条有逼格的macbook";
}
}复制代码
我来解释一下上面的代码,Macbook 和 Computer 是继承关系,Mouse 是一个trait ,Macbook 使用 use 关键字将 Mouse 注入到本身体内,此刻 Macbook 的 use 有点像yii2的 behaviors 函数。
接下来看看使用状况
$model= new Macbook ();
$model->say();// 我是一条有逼格的macbook
$model->sayName(); // 我是一台电脑
$model->click(); // 鼠标点击了一下复制代码
很高兴的是 trait 也一样注入了 Macbook 类加强了其功能,可是和行为不一样是咱们必须经过修改 Macbook 类代码实现,而yii2的行为能够经过动态绑定来实现对 Macbook 类的零修改。关于动态绑定能够参考以前干货文章 传送门
这个问题在行为和 trait 中都会存在,当使用它们的类、继承的类中具备相同成员时谁会被使用?
没明白么?那看个人这个图。
在顺序上略有不一样。
什么意思那,就是一个类同时使用了多个 trait 的状况,看下面代码。
trait Mouse {
public function click() {
echo "鼠标点击了一下";
}
}
trait Keyboard{
public function click() {
echo "键盘点击了一下";
}
}
class Macbook {
use Mouse,Keyboard;
}
$model = new Macbook();
$model->click();复制代码
咱们看看结果
这个时候咱们必须人工参与,使用下面的关键词
咱们来讲明下,仍是上面的例子
...
class Macbook {
use Mouse,Keyboard {
Mouse::click insteadof Keyboard;
}
}
$model = new Macbook();
$model->click();复制代码
结果输出了 “鼠标点击了一下”,由于咱们use的时候告诉php Mouse::click insteadof Keyboard,当冲突的时候使用Mouse的click代替Keyboard的同名方法。
固然咱们还可使用别名as,注意as没法替代insteadof,可是它可让被替代者以其余的名字运行。
...
class Macbook {
use Mouse,Keyboard {
Mouse::click insteadof Keyboard;
Keyboard::click as keyClick;
}
}
$model = new Macbook();
$model->click();
$model->keyClick();复制代码
看看结果
咱们解决了冲突。
而对于yii2而言则按照先附加行为的优先权自动解决,并不会产生错误,具体如何解决本篇再也不重复,能够去看下 揭秘yii2中行为的方法是如何注入到组件类中去的~ 这篇。
固然这种冲突解决方法会将后面的同名函数雪藏,而 trait 则能够将其经过as关键词再次启动起来。可是这个问题并不大,此种情景咱们能够有太多方法解决了。
event是个不能忽视的存在,经过前几篇咱们都知道行为+事件能够拥有不少炫酷的注入能力,那么trait ?
固然也能够,可是会麻烦不少,我来举个例子。
// @app\components\EventTrait.php
namespace app\components;
use app\models\User;
trait EventTrait {
public function initEvent(){
User::on(User::EVENT_LOOK_ME,function(){
echo "i am event";
});
}
}
// @app\models\User.php
class User extends \yii\db\ActiveRecord {
...
const EVENT_LOOK_ME = 'event_look_me';
use EventTrait;
...
}
// 在action中
$model = new User();
$model->initEvent();
$model->trigger(User::EVENT_LOOK_ME);复制代码
虽然也能够实现,可是天然没有行为来得容易,对代码的侵入性也太强,不建议这样用。
固然根据官方还有不少,好比行为可配置等,这些由于前几篇都已经进行了讲解,这里再也不重复。
总体来讲,yii2行为和trait 均可以解决单继承问题,而且也具备很不错的注入和组合能力,可是在各方面行为和yii2其余模块整合更好一点,所以推荐用yii2的行为。
不过这不是说你能够放弃 trait 了,记住,行为只能服务于组件类,可是yii2的世界里还有不是组件类的孩子们,请思考。
最后说一句,今天七夕,祝兄弟连全部有媳妇的、有媳妇的节日快乐,没媳妇的赶忙code。