php的多继承实现

  记得有一道面试题问php是否支持多继承?

  答案:不可以,只支持单继承。

  如何实现多继承呢?

  答案:可以使用 interface 或 trait 实现 。

  为什么会想到这个问题,因为想到如果类继承多个接口,然后他们之间还有相同的属性和方法会引用谁的方法或属性,谁又会被覆盖?

  总结:

    1.使用 interface 声明类不能被实例化,并且属性必须是常量,方法不能有方法体 

    2.trait 声明的类不能被实例化,由use引入,会覆盖父类的相同属性及方法,如果有多个use,那么按顺序下面的覆盖最上面的相同的属性及方法

 

  接口是什么?

  使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。

  接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。

  接口中定义的所有方法都必须是公有,这是接口的特性。

 

 

  trait是什么?

 

  看上去既像类又像接口,其实都不是,Trait可以看做类的部分实现,可以混入一个或多个现有的PHP类中,

  其作用有两个:表明类可以做什么;提供模块化实现。

  Trait是一种代码复用技术,为PHP的单继承限制提供了一套灵活的代码复用机制。

  参考文章

   接口:https://www.cnblogs.com/minigrasshopper/p/7754512.html

   trait:https://blog.csdn.net/lemony521/article/details/78322652

 

php接口interface的使用

接口是什么?

使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。

接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。

接口中定义的所有方法都必须是公有,这是接口的特性。

 

什么时候用接口?

1、定规范,保持统一性;

2、多个平级的类需要去实现同样的方法,只是实现方式不一样

 

接口使用规范

  • 接口不能实例化
  • 接口的属性必须是常量
  • 接口的方法必须是public【默认public】,且不能有函数体
  • 类必须实现接口的所有方法
  • 一个类可以同时实现多个接口,用逗号隔开
  • 接口可以继承接口【用的少】

 

复制代码
interface usb{
    const brand = 'siemens';    // 接口的属性必须是常量
    public function connect();  // 接口的方法必须是public【默认public】,且不能有函数体
}
// new usb();  // 接口不能实例化

// 类实现接口
class Android implements usb{
    public function connect(){  // 类必须实现接口的所有方法
        echo '实现接口的connect方法';
    }
}


interface usbA{
    public function connect();
}

interface usbB{
    public function contact();
}

// 类可以同时实现多个接口
class mi implements usbA,usbB{
    public function connect(){

    }
    public function contact(){

    }
}
复制代码

 

php中trait的使用


1、php中的trait是啥?

看上去既像类又像接口,其实都不是,Trait可以看做类的部分实现,可以混入一个或多个现有的PHP类中,其作用有两个:表明类可以做什么;提供模块化实现。Trait是一种代码复用技术,为PHP的单继承限制提供了一套灵活的代码复用机制。

2、PHP版本要求:
php5.4开始引入trait,其目的就是在于减少代码的重复,增加代码的复用性。

3、trait的使用场景:
试想这样一种情况,当有一个方法需要在很多的类中使用时,该怎么处理?
通常一般的处理方式会是,写一个基础类,在基类中实现这个方法,然后所有类都继承这个基类。

这是一种处理方法,但不是最好的处理方式。通常采用继承的情况是:几个类具有很大的相似性。比如人作为一个基类,学生、工人、等继承“人”这个基类来扩展。

由此,trait的作用就出来了,trait 可以在多个类中使用。

4、trait如何使用:
引用PHP手册中的例子:

例子一

<?php
trait ezcReflectionReturnInfo {
    function getReturnType() { /*1*/ }
    function getReturnDescription() { /*2*/ }
}

class ezcReflectionMethod extends ReflectionMethod {
    use ezcReflectionReturnInfo;
    /* ... */
}

class ezcReflectionFunction extends ReflectionFunction {
    use ezcReflectionReturnInfo;
    /* ... */
}
?>

 

 


1、先声明一个trait;
2、在类中使用use将该trait引入。
是不是非常简单(手动逃)?需要注意的是trait的优先级。

5、trait的优先级

(敲黑板)从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。

优先级:自身方法>trait的方法>继承的方法(就是这样子的。)

看例子

<?php
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

class TheWorldIsNotEnough {
    use HelloWorld;
    public function sayHello() {
        echo 'Hello Universe!';
    }
}

$o = new TheWorldIsNotEnough();
$o->sayHello();//输出是 Hello Universe!
?>


还有一点需要注意的是:多个trait的使用。

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World';
    }
}

class MyHelloWorld {
    use Hello, World;
    public function sayExclamationMark() {
        echo '!';
    }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>

 

 


总结:Trait是一种代码复用技术,为PHP的单继承限制提供了一套灵活的代码复用机制。

附:以上是trait的基本使用,其还有几个比较高级的使用注意点,详细的使用方法可以参见PHP手册,这里给出链接:PHP手册中trait的使用!以上内容中的例子都是来自于该手册。

参考:
1. http://php.net/manual/zh/language.oop5.traits.php
2. http://laravelacademy.org/post/4281.html
3. http://www.jianshu.com/p/47f0cdbe9b2c

 

posted @ 2019-02-17 22:25  夏秋初  阅读(7689)  评论(0编辑  收藏  举报