yii2行为和Trait

这多是你们最疑问的地方,到底有和不一样。php

进入咱们本身的解释以前,我先把yii2官方的说法粘贴一份过来,这是一个咱们在选择用行为仍是trait的一个标准。html

官方的说明

尽管行为在 "注入" 属性和方法方面相似于 trait ,它们在不少方面却不相同。如上所述,它们各有利弊。它们更像是互补的而不是相互替代。yii2

行为的优点

  • 行为类像普通类支持继承。另外一方面,trait 能够视为 PHP 语言支持的复制粘贴功能,它不支持继承。app

  • 行为无须修改组件类就可动态附加到组件或移除。要使用 trait,必须修改使用它的类。yii

  • 行为是可配置的而 trait 不能。函数

  • 行为以响应事件来自定义组件的代码执行。spa

  • 当不一样行为附加到同一组件产生命名冲突时,这个冲突经过先附加行为的优先权自动解决。而由不一样 trait 引起的命名冲突须要经过手工重命名冲突属性或方法来解决。code

trait 的优点

  • traits 比起行为更高效,由于行为是对象,消耗时间和内存。component

  • IDE 对 trait 更友好,由于它们是语言结构。cdn

  • 行为只能服务于组件类,而 trait 没有这个限制。

总结一下

经过上面的说明,总结来讲就一条:用行为、用行为、用行为。

-------------------我是分割线------------------------

虽然咱们已经会了行为,官方也说你就用行为就好了。可是咱们仍是有必要了解下traits,它究竟是什么?

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 的方法,而 trait 则覆盖了被继承的方法。
  • 对于行为,优先顺序是来自当前类的成员覆盖了被继承的方法,而继承的方法则覆盖了行为的方法。

没明白么?那看个人这个图。

alt
alt

在顺序上略有不一样。

多个组合成员名称冲突问题

什么意思那,就是一个类同时使用了多个 trait 的状况,看下面代码。

trait Mouse {
    public function click() {
        echo "鼠标点击了一下";
    }
}

trait Keyboard{
    public function click() {
        echo "键盘点击了一下";
    }
}

class Macbook {
    use Mouse,Keyboard;
}

$model = new Macbook();
$model->click();复制代码

咱们看看结果

哎

很不幸,对于此种情景PHP并无给出自动处理方案,直接抛出了致命error。

这个时候咱们必须人工参与,使用下面的关键词

  • insteadof
  • as

咱们来讲明下,仍是上面的例子

...
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();复制代码

看看结果

alt
alt

咱们解决了冲突。

yii2的多行为成员冲突问题

而对于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。


相关文章
相关标签/搜索