zoukankan      html  css  js  c++  java
  • 【多继承】PHP使用trait或者是组合的模式来实现多继承【原创】

    PHP的类继承只能是单继承,不能多继承,如果想要实现多继承的话,可以使用接口的方式来多继承,但是如果不想使用接口的方式来实现多继承的话,可以考虑使用trait来实现,当然也可以使用组合模式来实现。trait是PHP 5.4新增的代码复用的方法,
    Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。

    Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。

    通常在类中使用use关键字声明要组合的Trait名称,而具体某个Trait的声明使用trait关键词,Trait不能直接实例化。
    代码如下:
    1
    <?php
    2
    /**
    3
     * Traits可以多重继承,可以看做是一种加强型的接口
    4
     */
    5
    6
    trait Hello
    7
    {
    8
        public function sayHello()
    9
        {
    10
            echo 'Hello ';
    11
        }
    12
    13
        public function aaa()
    14
        {
    15
            echo 'AAA';
    16
        }
    17
    }
    18
    19
    trait World
    20
    {
    21
        public function sayWorld()
    22
        {
    23
            echo 'World';
    24
        }
    25
    }
    26
    27
    class MyHelloWorld
    28
    {
    29
        use Hello, World;
    30
    31
        public function sayExclamationMark()
    32
        {
    33
            echo '!';
    34
        }
    35
    36
        // 会覆盖掉Hello中的aaa方法
    37
        public function aaa()
    38
        {
    39
            echo 'AAAAA';
    40
        }
    41
    }
    42
    43
    $obj = new MyHelloWorld();
    44
    $obj->sayHello();
    45
    $obj->sayWorld();
    46
    $obj->sayExclamationMark();
    47
    $obj->aaa();
    48
    49
    // 输出:
    50
    // Hello World!AAAAA
    51
    代码中使用两个trait来实现了多继承。
    注意:两个trait中不能出现同样的方法,如果有同名的方法时,会产生致命错误。
    注意:并且MyHelloWorld类中也有aaa方法,会覆盖Hello trait中的aaa方法。

    上面的代码也可以通过组合的模式来实现,代码如下:
    <?php
    /**
     * 使用组合的方式也可以达到 1_12_trait.php 的效果
     */
    
    class Hello2
    {
        public function sayHello()
        {
            echo 'Hello ';
        }
    
        public function aaa()
        {
            echo 'AAA';
        }
    }
    
    class World2
    {
        public function sayWorld()
        {
            echo 'World';
        }
    
        public function aaa()
        {
            echo 'AAAA';
        }
    }
    
    class MyHelloWorld2
    {
        public $obj = [];
    
        public function __construct()
        {
            $this->obj['Hello2'] = new Hello2();
            $this->obj['World2'] = new World2();
        }
    
        public function sayExclamationMark()
        {
            echo '!';
        }
    
        public function __call($name, $arguments)
        {
            foreach ($this->obj as $value) {
                if (method_exists($value, $name)) {
                   return $value->$name();
                    // 也可以用 return call_user_func([$value, $name]);
                }
            }
    
            if (!method_exists($this->obj['Hello2'], $name) && !method_exists($this->obj['World2'], $name)) {
                echo "
    不存在此方法";
            }
    
            return true;
        }
    
        // 会覆盖其他类的aaa方法
        public function aaa()
        {
            echo 'AAAAA';
        }
    }
    
    $obj = new MyHelloWorld2();
    $obj->sayHello();
    $obj->sayWorld();
    $obj->saywhat();
    $obj->aaa();
    $obj->sayExclamationMark();
    
    // 输出:
    // Hello World!AAAAA


    显而易见,通过trait来实现的话代码量少得多并且可读性也要高得多。




  • 相关阅读:
    node
    github
    [模块] pdf转图片-pdf2image
    python 15 自定义模块 随机数 时间模块
    python 14 装饰器
    python 13 内置函数II 匿名函数 闭包
    python 12 生成器 列表推导式 内置函数I
    python 11 函数名 迭代器
    python 10 形参角度 名称空间 加载顺序
    python 09 函数参数初识
  • 原文地址:https://www.cnblogs.com/linewman/p/9918117.html
Copyright © 2011-2022 走看看