php面向对象之trait
trait的使用技巧
trait是php5.4以后新增加的一个功能,可以将多个类中,共用的一些属性和方法提取出来做来公共trait类,就像是装配汽车的配件,如果你的类中要用到这些配件,就直接用use导入就可以了,相当于把trait中的代码复制到当前类中.
因为trait不是类,所以不能有静态成员,类常量,当然也不可能被实例化。
其实一个类中的代码,可以分为二大部分:一是我们自己写的代码,暂且叫私有代码吧,还有一部分就是公共代码了,之前主要是由父类代码组成。现在你的类中的公共代码又多一个新成员:trait类代码。
如果说:继承可以纵向扩展一个类,那么trait就是横向扩展一个类功能
下面以实例进行演示:
//1创建一个trait类Test1

<?php
trait Test1
{
public $name = 'PHP中文网'; //trait类中可以用属性
public function hello1() //trait类中主要成员是方法
{
return 'Test1::hello1()';
}
}
//2.创建triat类Test2
trait Test2
{
function hello2()
{
return 'Test2::hello2()';
}
}
//3.创建Demo1类
class Demo1
{
use Test1, Test2;
}
//进行测试
$obj = new Demo1;
echo $obj->hello1(); //访问trait类Test1中的hello1()
echo '<hr>';
echo $obj->name; //访问ttrait类Test1中的$name属性
echo '<hr>';
echo $obj->hello2(); //访问ttrait类Test1中的hello2()

trait可以互相嵌套,一个trait类中可以用use导入另一个trait类,理解成代码复制就可以了.
例如本例中,在Test2中要用到Test1中的代码,我们只要改动二个地方就可以了。
一是在Test2中用use Test1;导入Test1中的代码,
二是在Demo1类中的,去掉对Test1的引用,只保留对Test2的引用,想想这是为什么?给大家当作一个思考题吧~
修改后的代码如下:
//1创建一个trait类Test1

<?php
trait Test1
{
public $name = 'PHP中文网'; //trait类中可以用属性
public function hello1() //trait类中主要成员是方法
{
return 'Test1::hello1()';
}
}
//2.创建triat类Test2
trait Test2
{
use Test1;
function hello2()
{
//在Test2中访问Test1中的属性name,注意语法与普通类是一样的
return 'Test2::hello2()'.$this->name;
}
}
//3.创建Demo1类
class Demo1
{
// use Test1, Test2;
use Test2;
}
//进行测试
$obj = new Demo1;
echo $obj->hello1(); //访问trait类Test1中的hello1()
echo '<hr>';
echo $obj->name; //访问ttrait类Test1中的$name属性
echo '<hr>';
echo $obj->hello2(); //访问ttrait类Test1中的hello2()

刚才说过,类中导入的公共代码,除了trait方法集,还可以有父类,如果在子类中访问父类中的成员,大家应该很熟悉了,现在一个类除了可以从父类继承成员,还可以从trait类中继承,那么有一个问题就不可避免了,如果父类和trait类中的成员命名冲突怎么办?说人话,就是重名了怎么办?下面我们以方法重名来演示一下处理方案。
再创建一个类Demo,做为Demo1类的父类。
//3.创建父类Demo

class Demo
{
//在父类中创建一个与Test2重名的方法hello2()
public function hello2()
{
return '父类Demo::hello2()';
}
}

代码如下:

//1创建一个trait类Test1
trait Test1
{
public $name = 'PHP中文网'; //trait类中可以用属性
public function hello1() //trait类中主要成员是方法
{
return 'Test1::hello1()';
}
}
//2.创建triat类Test2
trait Test2
{
use Test1;
function hello2()
{
//在Test2中访问Test1中的属性name,注意语法与普通类是一样的
return 'Test2::hello2()'.$this->name;
}
}
//3.创建父类Demo
class Demo
{
public function hello2()
{
return '父类Demo::hello2()';
}
}
//4.创建Demo1类
class Demo1 extends Demo
{
// use Test1, Test2;
use Test2;
}
//进行测试
$obj = new Demo1;
echo $obj->hello1(); //访问trait类Test1中的hello1()
echo '<hr>';
echo $obj->name; //访问ttrait类Test1中的$name属性
echo '<hr>';
echo $obj->hello2(); //访问ttrait类Test1中的hello2()

再次访问,会发现,结果与之前完全一样没有任何变化,父类Demo中的hello2方法好像隐身了,压根不存在一样的。事实上,父类Demo中的hello2方法当然是存在的,只是被trat类Test2中的同名方法hello2覆盖掉了,原因就是:trait类中的同名方法,访问优先级大于父类的同名方法。
如果我们就想访问父类中的hello2方法,怎么办呢?只有一个办法,要么父类方法改名,要么Test2中的方法改名,我们把Test2中的hello2方法改成hello3,再次访问,就可以看到父类的执行结果了。
那么,我们再进一点想一下,如果在子类也有一个hello2方法呢?那么结果会是什么样?
我们来试一下,在Demo1类中添加如下代码:

//4.创建Demo1类
class Demo1 extends Demo
{
// use Test1, Test2;
use Test2;
//在Demo1类中创建与Test2和父类Demo中同名的方法hello2()
public function hello2()
{
return 'Demo1::hello()';
}
}

在浏览器再次方法,果然不出所料,子类Demo1中的hello2方法的执行结果覆盖掉了Test2中的同名方法
现在我们总结一下在同一个类中,同名方法的优先级:子类>Trait类>父类,与就是说,谁离调用者越近,谁的优先级就越高。
下面我们再讨论最后一个问题:如果trait类中方法重名了,怎么办?如果是trait类中被所有类共享的方法集,重名的可能性是非常大的。
下面我们修改一下代码,删除一些用不到代码:

//1创建一个trait类Test1
trait Test1
{
public function hello()
{
return 'Test1::hello()';
}
}
//2.创建triat类Test2
trait Test2
{
function hello()
{
return 'Test2::hello()';
}
}
//3.创建类Demo
class Demo
{
use Test1, Test2{
//用Test1中的hello()方法替代Test2中的同名方法
Test1::hello insteadof Test2;
//Test2中的hello()方法用别名访问
Test2::hello as test2Hello;
} //这里千万不要加分号 ;
} //进行测试
$obj = new Demo;
echo $obj->hello(); //访问Test1中的hello()
echo '<hr>';
echo $obj->test2Hello();//别名访问Test2中的hello()
php面向对象之trait的更多相关文章
- Scala入门系列(八):面向对象之trait
基础知识 1 将trait作为接口使用 此时Trait就与Java中的接口非常类似,不过注意,在Scala中无论继承还是trait,统一都是extends关键字. Scala跟Java 8前一样不支持 ...
- Scala基础:面向对象之trait
trait类似于java中的interface,但是有所不同 Scala中的trait是一种特殊的概念: 首先先将trait作为接口使用,此时的trait就与Java中的接口 (interface)非 ...
- scala(三)
一.面向对象编程——类 1.定义一个简单的类 class HelloWorld { private var name = "leo" def sayHello() { print( ...
- 第2节 Scala中面向对象编程:12、13、14、15、16、trait
6.4. Scala中面向对象编程之trait 6.4.1. 将trait作为接口使用 Scala中的trait是一种特殊的概念: 首先先将trait作为接口使用,此时的trait就与Java ...
- Atitit usbQb212 oo 面向对象封装的标准化与规范解决方案java c# php js
Atitit usbQb212 oo 面向对象封装的标准化与规范解决方案java c# php js 1.1. 封装性是面象对象编程中的三大特性之一 三个基本的特性:封装.继承与多态1 1.2. 魔 ...
- PHP类与面向对象
PHP常量PHP常量大写PHP常量用define函数或const关键字定义一个常量一旦被定义,就不能再改变或者取消定义.在 PHP 5.3.0 以后,可以使用 const 关键字在类定义之外定义常量. ...
- Scala中的语言特性是如何实现的(3) -- Trait
我的新博客地址:http://cuipengfei.me/blog/2013/10/13/scala-trait/ 我在Coursera上跟了一门叫做Functional Programming Pr ...
- trait与policy模板技术
trait与policy模板技术 我们知道,类有属性(即数据)和操作两个方面.同样模板也有自己的属性(特别是模板参数类型的一些具体特征,即trait)和算法策略(policy,即模板内部的操作逻辑). ...
- PHP面向对象的小总结
面向对象特性: *重用性 (每个模块都可以在项目中重复使用) *灵活性 (每个模块都很轻松被替换更改的) *拓展性(在模块上添加新功能是很方便的) 类和对象的关系(类生成对象) 物以类聚:相同特性的 ...
随机推荐
- docker 系列之 docker安装
Docker支持以下的CentOS版本 CentOS 7 (64-bit) CentOS 6.5 (64-bit) 或更高的版本 前提条件 目前,CentOS 仅发行版本中的内核支持 Docker. ...
- Hadoop---日志服务器
Hadoop---日志服务器 1.历史服务器: 启动: 1)测试使用: 1.做一个任务: 2.接受任务: 3.执行任务: 4.执行任务完成: 2)日志文件产生: 成功后: 失败后: 点击进入His ...
- Scheduler & Task & Worker & Thread & Request & Session & Connection of SQL Server
MSSQL一直以来被人们认为简单.好学,但等到大家掌握了入门操作,深入理解起来又觉得非常的“拧巴”,尤其是对用惯了Oracle的同学来说,究其根本原因,无非是MSSQL引入和暴露了太多的概念.细节和理 ...
- spring context 继承
<web-app> <display-name>Archetype Created Web Application</display-name> <conte ...
- 使用VAE、CNN encoder+孤立森林检测ssl加密异常流的初探——真是一个忧伤的故事!!!
ssl payload取1024字节,然后使用VAE检测异常的ssl流. 代码如下: from sklearn.model_selection import train_test_split from ...
- Web应用的统一异常处理(二十四)
我们在做Web应用的时候,请求处理过程中发生错误是非常常见的情况.Spring Boot提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来 ...
- Sql server中如何将表A和表B的数据合并(乘积方式)
sql server中如何将表A 和表B的数据合并成乘积方式,也就是说表A有2条数据,表B有3条数据,乘积后有6条数据, 这就要用到sql中的笛卡尔积方式了 1.什么是笛卡尔积 笛卡尔积在SQL中的实 ...
- read later
https://groups.google.com/forum/#!msg/pylearn-users/FYtpaQKoC4c/ubitO_JUC1kJ 网上论坛 发布回复 ...
- 这本小书的目的是引导你进入 React 和 Webpack 的世界。他们两个都是非常有用的技术,如果同时使用他们,前端开发会更加有趣。
https://fakefish.github.io/react-webpack-cookbook/index.html
- 架构之路:nginx与IIS服务器搭建集群实现负载均衡(三)
参考网址:https://blog.csdn.net/zhanghan18333611647/article/details/50811980 [前言] 在<架构之路:nginx与IIS服务器搭 ...