trait

peter-yan 2018-02-02 原文

trait

参考

引文

在php中,为实现代码复用,有了继承,但是一个类只能继承一个父类,不支持多继承,接口支持多实现,但是接口又不太一样,接口对外负责功能调用声明,不负责实现,由实现了接口的类去实现具体功能逻辑,严格意义上来说,不算代码复用,从php5.4开始,php实现了另外一种代码复用的方法,就是下文即将要说的trait。

trait

trait是为扩展类似php单继承的一种代码复用机制,解除单继承语言的限制,使开发人员能够自由地在不同层次结构中组合复用method。trait本身不能实例化,它依托于class存在。传统继承是上下层面的关系,trait则为水平层面的组合。

优先级

对于相同方法名的方法而言,当前类的方法覆盖trait方法,trait中方法覆盖继承的父类方法

class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
    
    public function sayPeter() {
        echo "\nhello trait peter\n";
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
    public function sayPeter() {
        echo "\nhello class peter\n";
    }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayPeter();

输出

 多个trait

在类中,可以声明多个trait,将多个trait组合到一个类中

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冲突

如果trait之间定义了同名的方法,类中又组合了有同名方法的trait,会出现命名冲突,这个时候可以使用insteadof指明调用冲突方法中的某一个。trait中可以用as操作符为某个方法引入别名,注意引入别名并不会对原方法重命名,别名不能和已包含的trait中方法名重复

trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
    public function helloPeter() {
        echo "hello peter\n";
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
    public function helloAlice() {
        echo "hello alice\n";
    }
}

class Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}

class TalkerAs {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}

class TalkerHello {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        // A::helloPeter as helloAlice; 别名不允许和已包含trait中方法重名
    }
}

$talker = new Talker();
$talker->smallTalk();
$talker->bigTalk();
echo "\n";
$talkerAs = new TalkerAs();
$talkerAs->smallTalk();
$talkerAs->bigTalk();
$talkerAs->talk();

输出

trait组合trait

正如class可以使用多个trait,trait也可以使用trait

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

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

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

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

输出

抽象成员方法

在trait中可以定义抽象方法,类中如果要使用trait,必须要实现trait中的抽象方法

trait Hello {
    public function sayHelloWorld() {
        echo 'Hello ' . $this->getWorld() . "\n";
    }
    abstract public function getWorld();
}

class MyHelloWorld {
    private $world;
    use Hello;
    public function getWorld() {
        return $this->world;
    }
    public function setWorld($val) {
        $this->world = $val;
    }
}

$o = new MyHelloWorld();
$o->sayHelloWorld();
$o->setWorld('world');
$o->sayHelloWorld();

输出

 属性

trait中也可以定义属性,但要注意trait定了某个属性后,使用该trait的类中就不能定义同样名称的属性,否则会产生fatal error。(属性如果是兼容的(同样的访问控制符和默认值),就不会产生fatal error,但在php7之前,会有E_STRICT提醒)

trait PropertiesTrait {
    public $same = true;
    public $different = false;
}

class PropertiesExample {
    use PropertiesTrait;
    public $same = true; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒
    public $different = true; // 致命错误
}

php5.6

php7.1

 

发表于 2018-02-02 15:39 lvp 阅读() 评论() 编辑 收藏

 

版权声明:本文为peter-yan原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/peter-yan/p/8404809.html

trait的更多相关文章

  1. PHP 对象基础知识

    最近开始重新学习对象知识,其实也算是初步深入学习对象和设计模式,希望自己会坚持下去,保持更新 初识PHP对象 […]...

  2. PHP开发中需要注意几点事项,新手少走弯路必备知识

    这篇文章主要介绍了PHP开发需要注意的几点事项总结,非常详细,需要的朋友可以参考下。新手多看看避免走弯路。 1 […]...

  3. PHP 处理时间

    PHP 处理时间 Posted on 2018-06-15 17:24 Obsesion* 阅读(… […]...

  4. PHP 判断当前日期是否是法定节假日或者休息日 (原)

      //判断日期是不是节假日或者双休日接口 @param time [时间(时间戳或者Y-m-d都可)] pu […]...

  5. PHP国密SM2\SM4对接Java SM2SignWithSM3 (招商银行云直联)

    添加composer 包:composer require lpilp/guomiSM2签名<?phpuse Mdanter\Ecc\Crypto\Key\PrivateKey;use Mdanter\Ecc\Crypto\Signat...

  6. php 扩展开发

    下载对应版本php源码 windows: buildconf configure 1、注意你的头文件的包含的顺 […]...

  7. php excel drawing 报错

    Division by zero in Classes\PHPExcel\Worksheet\BaseDraw […]...

  8. php魔术方法小结

    php魔术方法__construct()__construct(mixed ...$values = ""): voidPHP 允许开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合...

随机推荐

  1. 廖雪峰Python总结2

    廖雪峰Python总结2 1.切片 L[0:3]表示,从索引0开始,直到索引3为止,但是不包括索引3。如果第一 […]...

  2. golang常用的http请求操作

    之前用python写各种网络请求的时候写的非常顺手,但是当打算用golang写的时候才发现相对来说还是pyth […]...

  3. 新浪sina邮箱客户端配置

    接收协议:IMAP 接收邮箱服务器地址:imap.sina.com 端口:993 加密方法:TLS   发送协 […]...

  4. 油田系统三维布局可视化解决方案 – ITman彪叔

    油田系统三维布局可视化解决方案 最近和一家公司在谈一个项目合作,他们公司主要是做油田相关设备的,比如油罐车、压 […]...

  5. servlet HttpServletRequest 类 1

    a)HttpServletRequest 类有什么作用。   每次只要有请求进入 Tomcat 服务器,Tom […]...

  6. Unity 播放序列帧

    Unity 播放序列帧 前一阵子写了一个播放序列帧的小脚本,本以为只是临时用一用,但是后来发现这个脚本能频繁的 […]...

  7. KMP算法(——模板习题与总结)

      KMP算法是一种改进的模式匹配算法,相比于朴素的模式匹配算法效率更高。下面讲解KMP算法的基本思想与实现。 […]...

  8. 记一次 .NET 某流媒体独角兽 API 句柄泄漏分析

    一:背景 1. 讲故事 上上周有位朋友找到我,说他的程序CPU和句柄都在不断的增长,无回头趋势,查了好些天也没 […]...

展开目录

目录导航