PHP代码的多继承 -》 PHP代码复用新的姿势 trait
本文参考: 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的更多相关文章
- Java面向对象理解_代码块_继承_多态_抽象_接口
面线对象: /* 成员变量和局部变量的区别? A:在类中的位置不同 成员变量:在类中方法外 局部变量:在方法定义中或者方法声明上 B:在内存中的位置不同 成员变量:在堆内存 局部变量:在栈内存 C:生 ...
- Java基础进阶:继承重点摘要,继承详解,方法重写注意事项,方法重载与重写的区别,抽象类,代码块, 附重难点,代码实现源码,课堂笔记,课后扩展及答案
继承重点摘要 *继承的特点: 子类在初始化之前,一定要先完成父类数据的初始化 子类在初始化之前,一定要先访问父类构造,完成父类数据的初始化 系统在每一个构造方法中默认隐藏了一句super(); 如果我 ...
- Winform打砖块游戏制作step by step第5节---重构代码,利用继承多态
一 引子 为了让更多的编程初学者,轻松愉快地掌握面向对象的思考方法,对象继承和多态的妙用,故推出此系列随笔,还望大家多多支持. 二 本节内容---重构代码,利用继承多态 1. 主界面截图如下: 2. ...
- Java之同步代码块处理继承Thread类的线程安全问题
package com.atguigu.java; /** *//** * 使用同步代码块解决继承Thread类的方式的线程安全问题 * * 例子:创建三个窗口卖票,总票数为100张.使用继承Thre ...
- final、static、代码块、静态代码块、内部类、代码执行顺序
final final域使得确保初始化安全性(initialization safety)成为可能,初始化安全性让不可变形对象不需要同步就能自由地被访问和共享 作用在类上 ...
- 关于java构造函数,静态代码块,构造代码块,和普通代码块相关总结(一)
构造函数.构造代码块和静态代码块容易混淆,它们的执行条件和执行顺序也常常容易犯迷.这里就针对这些问题说一下我个人的一些理解,顺便对这部分内容做个小结. 一.构造函数 格式:类名(参数1,参数2,-){ ...
- java代码编译与C/C++代码编译的区别
Java编译原理 1.Java编译过程与c/c++编译过程不同 Java编译程序将java源程序编译成jvm可执行代码--java字节码. Java在编译过程中一般会按照以下过程进行: (1)JDK根 ...
- Swagger结合mustache模板生成后台接口代码、以及前后台建模代码
之前项目中使用的的thrift来建模,维护前后台模型以及rest接口,前台使用的是angular2: 但是使用thrift只能生成建模,后台的rest接口的Controller文件还是需要手动去写,一 ...
- Web前端开发最佳实践(9):CSS代码太太乱,重复代码太多?你需要精简CSS代码
前言 提高网站整体加载速度的一个重要手段就是提高代码文件的网络传输速度.之前提到过,所有的代码文件都应该是经过压缩了的,这可提高网络传输速度,提高性能.除了压缩代码之外,精简代码也是一种减小代码文件大 ...
随机推荐
- [转]ASP.NET Web API基于OData的增删改查,以及处理实体间关系
本文转自:http://www.cnblogs.com/darrenji/p/4926334.html 本篇体验实现ASP.NET Web API基于OData的增删改查,以及处理实体间的关系. 首先 ...
- C++Array类模板编写笔记
C++Array类模板 函数模板和类模板都属于泛型技术,利用函数模板和类模板来创建一个具有通用功能的函数和类,以支持多种不同的形参,从而进一步简化重载函数的函数体设计. 声明方法:template&l ...
- Java API 之 Properties 类
1.简介 在项目中我们经常看到一种格式极其干净的配置文件,如:config.properties.在Java的体系结构中也提供了API对properties文件进行读取和写入等操作,即:Propert ...
- JFrame自适应大小
pack();函数调用PreferedSize(); 所以对于组件要setPreferedSize();
- HTML5数据存储方案data与jQuery数据存储方案$.data()的区别
我们先看下$.fn.data()的使用,这个和$.data()是不一样的,前者是和某个jquery对象相关,后者则是全局方法.主要有data()和removeData()这2个实例方法.通过下面的例子 ...
- FLASK实现上传下载功能
#!-*-coding=utf-8-*- # from flask import Flask # # app = Flask(__name__) # # # @app.route('/') # def ...
- webapp 的简单开发
web app 的技术平台很多,如adobe phonegap.sencha touch.appcan(国产).dcloud(国产)平台.我选择了dcloud平台,原因:简单,容易上手. web ap ...
- 操作Hadoop集群
操作Hadoop集群 所有必要的配置完成后,将文件分发到所有机器上的HADOOP_CONF_DIR目录.这应该是所有机器上相同的目录. 一般来说,建议HDFS和YARN作为单独的用户运行.在大多数安装 ...
- CentOS 7运维管理笔记(1)----设置默认启动模式为GUI模式或命令行模式
昨天在虚拟机中安装CentOS 7时选择了GNOME模式安装,开机默认进入GUI模式.网上搜找修改为默认命令行模式的方法,看到说修改 /etc/inittab文件,在最低下一行添加 但是 使用 cat ...
- .NET开源工作流RoadFlow-流程运行-任务收回
如果一个任务则发送,又觉得还要想修改可以立即收回刚刚发送的任务. 任务收回条件:任务发送后下一步处理人还没有打开该任务,则在已办事项中会看到 收回 按钮,否则不能收回. 点击收回按钮再确认即可收回刚刚 ...