天天看点

trait特性,什么是trait,整理版

作为PHP5.4引入新特性trait,有不少读者感觉比较陌生。

本篇从背景、作用、使用三个方面分析trait,力求以最通俗的语言解释清楚。

背景

PHP在面向对象的设计时, 被设计为单继承. 什么叫单继承, 一个类A只能继承一个类B, 再由B类继承C类. 而不能A类同时继承B类和C类.

正确的写法:demo1.php

<?php

class C{}

class B extends C{}

class A extends B{}

$obj = new A;

var_dump($obj);

           

会得到一个对象

/home/vagrant/Code/blog/demo1.php:11:
object(A)[1]      

//注意

//A类同时继承B类和C类, 这样写是不允许的

例如:

<?php

class C{}
class B{}

class A extends B,C{}

$obj = new A;

var_dump($obj);


//代码是错误的。
( ! ) Parse error: syntax error, unexpected token ",", expecting "{" in /home/vagrant/Code/blog/demo2.php on line 6
           

说人话, 就是一个儿子只能有一个父亲, 但是反过来呢?一个父亲是可以有多个儿子的.

如果想A类既使用B的方法又使用C的方法, PHP提出了接口(Interface). PHP虽然是单继承, 但是可以多实现. 什么叫多实现, 一个类A可以同时实现B接口和C接口.(demo3.php)

<?php

interface C{}

interface B{}

class A implements B,C{}

//A类同时实现接口B和接口C, 这样是允许的


$obj = new A;

var_dump($obj);
           

同样会得到一个对象

/home/vagrant/Code/blog/demo3.php:11:
object(A)[1]      

作用

关键词: 假多继承, 代码复用, 类的包含

现在有这样一个场景

需求: A类既可以使用B类的方法又可以使用C的方法, A类和B类是继承关系, 但是B和C没有继承关系, 怎么解决?

方法:A类继承B类, 同时实现C接口(demo4.php)

<?php

interface C{
    public function ccc();
}

class B{
    public function bbb()
    {
        echo "我是B类的bbb方法<br>";
    }
}

class A extends B implements C{
    public function ccc()
    {
        echo "我是A类,我要实现接口C定义的方法<br>";
    }
}

$obj = new A;
$obj ->ccc();
$obj ->bbb();
~
~
           

强烈建议上面的代码,敲10遍以上。

(拓展: 接口)

接口不能被实例化

接口是为了规范显现它的子类,以达到统一的目的

接口中只有:常量和抽象方法

接口里的所有方法都是抽象方法,不能写方法体,并且,接口的抽象方法不需要写abstract。

子类继承接口的方法,叫 实现,所以说接口是用来实现的(涉及php基础知识)

如果这个时候有一个D类, 也要继承B类, 实现C接口, 需要重复的写这段代码(demo5.php)

<?php

interface C{
    public function ccc();
}

class B{
    public function bbb()
    {
        echo "我是B类的bbb方法<br>";
    }
}

class A extends B implements C{
    public function ccc()
    {
        echo "我是A类,我要实现接口C定义的方法<br>";
    }
}

class D extends B implements C{
    //这段代码是重复的
    public function ccc()
    {
        echo "我是D类,我要实现接口C定义的方法<br>";
    }
}
$obj = new A;
$obj ->ccc();
$obj ->bbb();
           

使用

思考: 能不能将这部分重复的代码定义在一个类中, A类和D类包含这个类呢?

这个时候trait应用而生(demo6.php)

<?php

interface C{
    public function ccc();
}

class B{
    public function bbb()
    {
        echo "我是B类的bbb方法<br>";
    }
}

trait E{
    public function ccc()
    {
        echo "我是trait,我实现了ccc方法<br>";
//      echo "我是trait,我是".__CLASS__."类,我实现了ccc方法<br>";
    }
}

class A extends B implements C{
    use E;
}

class D extends B implements C{
    use E;
}


$obj = new A;
$obj ->ccc();
$obj ->bbb();
           

运行结果如下:

我是trait,我实现了ccc方法

我是B类的bbb方法

上面的代码可以继续优化一下

通过上面的用法, 我们就可以这样总结

  1. trait本质上还是一个类
  2. 接口(interface)规定了方法的定义, trait规定了方法的实现
  3. 可以认为A类D类等等其他类在需要ccc方法的时候包含了trait

综上, trait是PHP实现多继承的一种折中的方法, 姑且叫它"假多继承", 可以认为一个类(A类)包含了另一个类E(trait), 最终目的是为了实现代码复用.