本文参考:  http://php.net/language.oop5.traits

一、什么是trait

从PHP 5.4.0 开始 PHP 实现了一种新的代码复用方式 trait。

二、trait解决了什么问题

trait 的出现是为了解决类似PHP的单继承语言而准备的一种代码复用机制,让开发人员能够在不能层次结构内独立的类中复用 method。

三、跟其它语言相比,trait 有什么 好处

Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。

四、该如何使用trait

  • 示例1,如何使用 trait

    <?php
    trait ezcReflectionReturnInfo {
    function getReturnType() { /*1*/ }
    function getReturnDescription() { /*2*/ }
    } class ezcReflectionMethod extends ReflectionMethod {
    use ezcReflectionReturnInfo;
    /* ... */
    } class ezcReflectionFunction extends ReflectionFunction {
    use ezcReflectionReturnInfo;
    /* ... */
    }
    ?>
  • 示例2 ,trait 与 class 方法优先级问题
    trait 方法会覆盖基类中的方法,当前类中的方法会覆盖 trait 方法
    <?php
    class Base {
    public function sayHello() {
    echo 'Hello ';
    }
    } trait SayWorld {
    public function sayHello() {
    parent::sayHello();
    echo "World!\r\n";
    }
    } class MyHelloWorld extends Base {
    use SayWorld;
    } class MyNewHelloWorld extends Base{
    use SayWorld;
    public function sayHello(){
    echo "Hello sunshine!\r\n";
    }
    } $o = new MyHelloWorld();
    $o->sayHello(); $b = new MyNewHelloWorld();
    $b->sayHello();
    ?>

    上面的代码会输出:

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUQAAAAuCAIAAADfkPcZAAAETklEQVR4nO2d25WsIBBFzcdUTKTXMhGymB/zMLT58AXUg5fYTs3Zf/eCBQi7UZpmhp+fn8/nMzBMbl2XeeSSTsZ5WdfVTWKGya00yuToRUzGLXjAcRGTRPJMTkkUggQV2AL4V0wzuR9KJdvvQ5Rhb1F4BdtML0+yi5JNoCVo0VoZ54UZd2yHp0anR+ouZfaFFqGkfXo1lFL09BfLzNTdu8i7KdtlR14+j1BNv4BUutRSpZKN94FkOBoURYpqEKSmZY4up30e3MYCg6rgZabVLNPouJNXDO4W5vSFGKGwMnJTtN7Uk9tkBuBmZJmv9PL5kHP16Qj90WVOT0sANEMePW+fRCAzZAaPAJnvQZYZADNA5lqSc7qNSb+mFRnLUQBUApmruVPm1LIPAGk6P2YnZyIbU1V2KyAz6AeRmXk3aBDuOzJPTgypJDUAmcELMCuzYMbkejgDmcELqJbZf2OUR2GLzOn9W2pQMWbuFjGvaqmNYlozgy1DkBn0o0rm1K5m5dLcDMmd1Sr+1Ew25eVu3t6rNkeNLZFZ2EMOmUEPKmTeR2i8+1uZXYtl3j27RvdeZu5w96bmINQ4L0eMdBGXief/SW/cQjO3Mq6IzPZxPwBkBk3wMmvTCTPu5KFYJzP36bBlzB3v59R8Gnk+LvuOq0WQDy0Z5SOJ+yUYZAY9KJc5mcGnQeZ4aBctlZ1T8OTWZZ72f8UTs15EQYFsVu4/xZh9VtnBv6L8MftPyHzIsS947RO1ZwxkBuaolLno5fULj9m7vtO+eL29Q8/XxJz/mP2QzAA0U7EAxh54MYzzfNvM3LwAdujrnL/y5dxCWpFcAKuXmbx0h+/vANxM1VdT+UeofOmrqYHIStzN/mqqXmbmp33OaRmxAgZauGXTiDwOv7NpxLs6monZJ2GhiHaZwxKOJTjIDPqA3zMDYATIDIARIDMARoDMABgBJ4104y+cGgUsAZm7USIz/939rWD7t3lwbFA3IDN4FpMnjbyDlz1mQ2bzQOZuQGbwLCaPDeIjBPWkzYx+QHJlUM8MyipCihCvHch/WU4/tyirLyCzeWweGyRUknU1KDHOEJ8ZFDY0pwgtQp7MxXXg+wIym8fmsUFS4HEsk5lz77oopwg9glh6boSCvoDM5jF6bNDAfCDQ1LTMYR1i4zKKSETQE5IRSvoCMpvH6LFBtKbJP64tvjNr9SorokpmLUJRX+AwE+tYPTYojhbX8SaZy4qAzKAnVo8NooRBSSvi+EUqykU8IDMencGG1WODhsllPF+Qp40imXOK6CtzUV8A61g/NkiKQL8fnosfsxNFPCFzfl/gMBP7mD02KF3FK/k4YbtxAYxL6y5zRkOHYYDM/wH8nhkAI0BmAIwAmQEwAmQGwAiyzGSZVNw1gp0IneAWwCxC/1iAskw3zgtW8Xj6ysx/Dfoq/NYwgyQYZ9WDqPI+PCZz2KVMif5tuL9CuTK3/yjWNL/kSiZTDjjUPwAAAABJRU5ErkJggg==" alt="" />

  • 示例3  同时使用多个 trait  通过逗号分隔,在 use 声明列出多个 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();
    ?>

    上面的代码会输出:

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAasAAAApCAIAAAAEfJFdAAACvElEQVR4nO3dy3GDMBRA0fRDK2rEM2pEXXijPqjFbiQLBAj0ASTzfffskhBknOGOQIzz9/l83u/36/X6A55MmbZtjTp1D+hc6W9BAQHIRQEByEUBAchFAQHIRQEByEUBAchFAQHIRQEByEUBAchFAQHIRQEByEUBAchFAQHIRQEByEUBAchFAQHIRQEByEUBAchFAQHItVMBlWmn5h/pv7jBLZQcRaPtXQ8XeBwKWOOXBWy0bVurm11eKICo/a+CF+c8z5gUrT4KCghcx/f7DQoY+U90FZU6p4DKJHeZ+VEFCgjc0JMLmMiJMnuEhgICN1RTQP8uWPrUrSlg96OSW4WNtpl9ej/IDuG9NP9gY/vNHeb4u1Y3FBC4jtICTsORi2BxAYNlhk0V9CeByrTTL/q9LA3hXpqeHeyWAkbeqPguKCBwvLICutN63KZLSWYet7mALk5jEtyYaxvhTQInu2q07fexPMSYr+F7qbuIicPsxhj32DeXAgJXkCxgbuISOVnT529ZAWNJ7TZcG4lhEjhkbLia9cOYHSIofVqm45F3igICl1BUwMUNfBUFnPdg05rJMNlTprVaua/mU8D8EBsGjG4a+2Zyn/usUQPIKLoKvkUB+6K4lQ83JfQyQwEB8coLuOmG3AlXwa55yi39dvcF9TgFXH8VfFABARyubCXETQKD813/bA5YvRLSN88YfwnEGBscxeJKSHkBgxuJ03uSAE5W+jRM/EL4d1fBqSG2lGNWuCB4q5+GKS9g+DCMNSa3IUshwJF+9UR0+uQ954lo77dnc77ohWpiiPoCTkfo12IoIHANsQICgAwUEIBcFBCAXBQQgFzZAiY/AvkZn/B8B5FVqUcK18wzS0KNtqwY4Td2L2D80cFLWfiUr8nJWXzmFb4PhxVw+ieNjOi/DXt9wOxyAeueDgBm/gHMH9X2J7bOCAAAAABJRU5ErkJggg==" alt="" />

  • 示例4 冲突的解决 

    如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。

    为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。

    <?php
    trait A {
    public function smallTalk() {
    echo 'a';
    }
    public function bigTalk() {
    echo 'A';
    }
    } trait B {
    public function smallTalk() {
    echo 'b';
    }
    public function bigTalk() {
    echo 'B';
    }
    } class Talker {
    use A, B {
    B::smallTalk insteadof A;
    A::bigTalk insteadof B;
    }
    } class Aliased_Talker {
    use A, B {
    B::smallTalk insteadof A;
    A::bigTalk insteadof B;
    B::bigTalk as talk;
    }
    }
    ?>
  • 示例5  使用trait来组成trait   正如 class 能够使用 trait 一样,其它 trait 也能够使用 trait。在 trait 定义时通过使用一个或多个 trait,能够组合其它 trait 中的部分或全部成员。
    <?php
    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();
    ?>

    上面例子会输出:

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAasAAAApCAIAAAAEfJFdAAACvElEQVR4nO3dy3GDMBRA0fRDK2rEM2pEXXijPqjFbiQLBAj0ASTzfffskhBknOGOQIzz9/l83u/36/X6A55MmbZtjTp1D+hc6W9BAQHIRQEByEUBAchFAQHIRQEByEUBAchFAQHIRQEByEUBAchFAQHIRQEByEUBAchFAQHIRQEByEUBAchFAQHIRQEByEUBAchFAQHItVMBlWmn5h/pv7jBLZQcRaPtXQ8XeBwKWOOXBWy0bVurm11eKICo/a+CF+c8z5gUrT4KCghcx/f7DQoY+U90FZU6p4DKJHeZ+VEFCgjc0JMLmMiJMnuEhgICN1RTQP8uWPrUrSlg96OSW4WNtpl9ej/IDuG9NP9gY/vNHeb4u1Y3FBC4jtICTsORi2BxAYNlhk0V9CeByrTTL/q9LA3hXpqeHeyWAkbeqPguKCBwvLICutN63KZLSWYet7mALk5jEtyYaxvhTQInu2q07fexPMSYr+F7qbuIicPsxhj32DeXAgJXkCxgbuISOVnT529ZAWNJ7TZcG4lhEjhkbLia9cOYHSIofVqm45F3igICl1BUwMUNfBUFnPdg05rJMNlTprVaua/mU8D8EBsGjG4a+2Zyn/usUQPIKLoKvkUB+6K4lQ83JfQyQwEB8coLuOmG3AlXwa55yi39dvcF9TgFXH8VfFABARyubCXETQKD813/bA5YvRLSN88YfwnEGBscxeJKSHkBgxuJ03uSAE5W+jRM/EL4d1fBqSG2lGNWuCB4q5+GKS9g+DCMNSa3IUshwJF+9UR0+uQ954lo77dnc77ohWpiiPoCTkfo12IoIHANsQICgAwUEIBcFBCAXBQQgFzZAiY/AvkZn/B8B5FVqUcK18wzS0KNtqwY4Td2L2D80cFLWfiUr8nJWXzmFb4PhxVw+ieNjOi/DXt9wOxyAeueDgBm/gHMH9X2J7bOCAAAAABJRU5ErkJggg==" alt="" />

除了这些特性,trait 还包括 抽象成员  静态成员  静态方法  属性 等特性,可以参考    http://php.net/language.oop5.traits

PHP代码的多继承 -》 PHP代码复用新的姿势 trait的更多相关文章

  1. Java面向对象理解_代码块_继承_多态_抽象_接口

    面线对象: /* 成员变量和局部变量的区别? A:在类中的位置不同 成员变量:在类中方法外 局部变量:在方法定义中或者方法声明上 B:在内存中的位置不同 成员变量:在堆内存 局部变量:在栈内存 C:生 ...

  2. Java基础进阶:继承重点摘要,继承详解,方法重写注意事项,方法重载与重写的区别,抽象类,代码块, 附重难点,代码实现源码,课堂笔记,课后扩展及答案

    继承重点摘要 *继承的特点: 子类在初始化之前,一定要先完成父类数据的初始化 子类在初始化之前,一定要先访问父类构造,完成父类数据的初始化 系统在每一个构造方法中默认隐藏了一句super(); 如果我 ...

  3. Winform打砖块游戏制作step by step第5节---重构代码,利用继承多态

    一 引子 为了让更多的编程初学者,轻松愉快地掌握面向对象的思考方法,对象继承和多态的妙用,故推出此系列随笔,还望大家多多支持. 二 本节内容---重构代码,利用继承多态 1. 主界面截图如下: 2.  ...

  4. Java之同步代码块处理继承Thread类的线程安全问题

    package com.atguigu.java; /** *//** * 使用同步代码块解决继承Thread类的方式的线程安全问题 * * 例子:创建三个窗口卖票,总票数为100张.使用继承Thre ...

  5. final、static、代码块、静态代码块、内部类、代码执行顺序

    final final域使得确保初始化安全性(initialization safety)成为可能,初始化安全性让不可变形对象不需要同步就能自由地被访问和共享 作用在类上               ...

  6. 关于java构造函数,静态代码块,构造代码块,和普通代码块相关总结(一)

    构造函数.构造代码块和静态代码块容易混淆,它们的执行条件和执行顺序也常常容易犯迷.这里就针对这些问题说一下我个人的一些理解,顺便对这部分内容做个小结. 一.构造函数 格式:类名(参数1,参数2,-){ ...

  7. java代码编译与C/C++代码编译的区别

    Java编译原理 1.Java编译过程与c/c++编译过程不同 Java编译程序将java源程序编译成jvm可执行代码--java字节码. Java在编译过程中一般会按照以下过程进行: (1)JDK根 ...

  8. Swagger结合mustache模板生成后台接口代码、以及前后台建模代码

    之前项目中使用的的thrift来建模,维护前后台模型以及rest接口,前台使用的是angular2: 但是使用thrift只能生成建模,后台的rest接口的Controller文件还是需要手动去写,一 ...

  9. Web前端开发最佳实践(9):CSS代码太太乱,重复代码太多?你需要精简CSS代码

    前言 提高网站整体加载速度的一个重要手段就是提高代码文件的网络传输速度.之前提到过,所有的代码文件都应该是经过压缩了的,这可提高网络传输速度,提高性能.除了压缩代码之外,精简代码也是一种减小代码文件大 ...

随机推荐

  1. MySql数据库与JDBC编程

    JDBC -- Java Database Connectivity,即Java数据库连接,通过使用JDBC就可以使用同一种API访问不同的数据库 SQL语句基础(SQL结构化查询语言) 能完成的任务 ...

  2. C#根据用户输入字符串,输出大写字母有几个,小写字母有几个

    static void Main(string[] args) { // 根据用户输入字符串,输出大写字母有几个,小写字母有几个. Console.WriteLine("请输入一行英文代码& ...

  3. List和Queue使用过程中的纪录

    业务需求: 发送特定的请求,根据返回的信息执行特定的事件. 目前的做法:把我的请求放入一个容器内,然后待到某一条件,就从这个容器把请求发送出去,等客户返回信息时,查询容器中对应请求中特定的事件.开始的 ...

  4. golang学习之interface与其它类型转换

    如下函数,将interface变量in转换为int: func formatTimeStamp(in interface{}, layout string) (out string) { timeSt ...

  5. sqlserver查询表字段描述(转)

    原文地址:https://blog.csdn.net/changhong009/article/details/29587063 --快速查看表结构(比较全面的) SELECT CASE WHEN c ...

  6. JavaScript switch语句

    JavaScriptswitch语句 switch语句用于基于不同的条件来执行不同的动作. JavaScript switch 语句 使用switch语句可以进行多项选择. 语法: switch( 变 ...

  7. 浮动的补充丶文本和字体属性丶background丶定位

    一丶浮动的补充 浮动的特性: 1. 浮动的元素脱标 2.浮动的元素互相贴靠 3.浮动的元素有"字围"效果 4.浮动的元素有收缩的效果 前提是标准文档流,margin的垂直方向会出现 ...

  8. 理解JS表达式

    表达式:是由运算元和运算符(可选)构成,并产生运算结果的语法结构. 基本表达式 以下在ES5中被称为基本表达式(Primary Expression) this.null.arguments等内置的关 ...

  9. 空白符对HTML结构的影响与解决方案

    何为空白符? 空白符: 空格.制表符.换行符 注意:浏览器在解析HTML时会把所有空白符合并成一个空格 空白符对HTML结构的影响 HTML5中<textarea>标签placeholde ...

  10. CentOS 7 禁用IPV6以提高网速

    方法 1 编辑文件/etc/sysctl.conf,$vi /etc/sysctl.conf添加下面的行: net.ipv6.conf.all.disable_ipv6 = net.ipv6.conf ...