PHP中Trait的使用

面向对象编程的三大特性是:抽象,继承,多态。我们都知道,PHP是一种单继承的语言,那么如何在PHP中如何实现多继承呢?

我们先来考虑这样一个需求: 我们的项目是多模块,多平台开发。我们会使用MVC分层,将操作数据库的方法放在M层,接收参数验证参数放在C层,V层用来渲染页面。那么有这样这样一组方法,需要在M层和C层都需要调用,怎么写这个方法呢?

方法①: 我们将方法写在 M层和C层的基类中, 分别继承。 虽然实现了需求,但是M层和C层的基类中还是会存在重复代码

方法②: 我们将方法写在公共的一个类,使用静态方法或者单例模式调用。 这样也可以实现需求,并且看起来没有什么问题。

那么我们再来思考一个问题:我们的项目是多模块,多后台登录,对于登录来讲, 两个模块中的控制器内容应该是相似的,因为他们的工作是相同的,接收登录的用户名密码并验证参数,交给模型处理并返回登录结果。那如何封装代码呢?

有的同学会说: 我们可以建一个登录的基类,两个模块分别继承就可以拥有登录的功能,并且维护起来也十分方便!

这样也实现了需求,但是缺点在于增加继承的深度,而且登录的父类还要去继承控制器的基类,继承的层度只会越来越深。

我们在来思考:在项目中我们的数据库中使用软删除(即删除是在数据库表中加入字段标记,而不是物理删除),我们的模型去继承软删除的基类就可以实现此方法呢? 假如现在我们想要在一些重要的模型中记录增删改查的记录,通过在模型的钩子(添加后,删除后,修改后)内记录日志,难道我们的模型还要去记录日志模型吗? 假如已经继承了软删除,如何再继承日志模型呢?

在php5.4 以后,php内加入了 trait 来解决多继承的问题。

trait 的目的在于减少代码的重复,增加复用性。

用法:使用trait 声明, 在要使用的类中使用关键字use ,不能被初始化。

trait LoginTrait
{
    public function loginAction()
    {
        //接收参数 验证参数
        //调用business
        echo 'success';
        echo '<br/>';
        //返回结果
    }
}

class AdminLogin
{
    use LoginTrait;
}

class ShopLogin
{
    use LoginTrait;
}

我们需要注意的是 trait 的优先级: 自身方法>trait的方法>继承的方法

class Login
{
    public function LoginAction()
    {
        echo 'success parent';
    }
}

trait LoginTrait
{
    public function loginAction()
    {
        //接收参数 验证参数
        //调用business
        echo 'success';
        echo '<br/>';
        //返回结果
    }
}

class AdminLogin extends Login
{
    use LoginTrait;

    public function loginAction()
    {
        echo 'success self';
    }
}

(new AdminLogin())->loginAction();

输出结果:success self

那么一个类是否可以use 多个 trait 呢? 答案是 可以的, 但是要注意的是,当use 的 多个 trait 中 有相同的方法时,会引起冲突,需要在子类中使用 insteadof 或者 as 解决。

trait LoginTrait2
{
    public function loginAction()
    {
        //接收参数 验证参数
        //调用business
        echo 'success2';
        echo '<br/>';
        //返回结果
    }
}

class AdminLogin extends Login
{
    use LoginTrait, LoginTrait2{
        LoginTrait2::loginAction insteadof LoginTrait;
        LoginTrait::loginAction as loginAction2;
    }

}

(new AdminLogin())->loginAction();
(new AdminLogin())->loginAction2();

输入结果: success2; success

Trait的应用:

如我们前面举到的例子: 软删除,日志模型,另外还有如:缓存模型、复用单例类的方法、复用多平台的控制器内容等等。 转载自剑花烟雨江南

评论

(= ̄ω ̄=)··· 暂无内容!

回复

您还未登录,请先登录或者注册