面向对象编程的三大特性是:抽象,继承,多态。我们都知道,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的应用:
如我们前面举到的例子: 软删除,日志模型,另外还有如:缓存模型、复用单例类的方法、复用多平台的控制器内容等等。 转载自剑花烟雨江南
评论