首页 > 编程语言 >【web开发】使用Trait解决PHP面向对象中类只支持单继承的限制

【web开发】使用Trait解决PHP面向对象中类只支持单继承的限制

时间:2023-06-16 23:34:35浏览次数:45  
标签:web use 继承 Trait 混入 使用 PHP 类中

前言

众所周知,PHP的面向对象和Java一样,类只支持单继承,即是一个类只能继承自一个父类,不能存在多个父类,这也很好理解,就像现实的人类社会一样,儿子继承自你的父亲,父亲继承自祖父。。。,但是在实际开发中很多时候我们想像c++一样使用多重继承。奈何PHP只能使用单继承,在Trait出现之前,在PHP中要想实现多继承,只能使用接口,只有接口是可以实现多继承的,一个类可实现多个接口,而且接口和接口之间是可以多继承的。我们一般所说的类只能支持单继承是指类与类之间的关系。但是毕竟接口中的方法都是抽象方法,没有具体的实现,实现接口需要实现接口中的所有方法,有时候并不是我们想要的,因为我们很多时候不但要规范开发,还要能够使代码的可重用性提高,甚至达到代码重复使用价值的最大化。

从PHP5.4开始,便开始引入Trait这个特性。Trait和类非常相似,甚至他们的声明方式都相当接近,除了类是使用Class修饰,Trait使用trait标识符修饰外,其他几乎一模一样,包括成员属性和成员方法的定义。类中的一般特性Trait基本都可以实现,但很多会疑问,Trait到底是不是类的替代呢?可以肯定Trait并不是用来代替类的。而是混入类中,Trait是为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用方法集。我们也可以简单理解为Trait是类的延伸。Trait和类组合的语义是定义一种方式来减少复杂性,避免传统多继承相关的典型问题。比如:需要同时继承两个抽象类,这是PHP所不支持的,Trait就是为了解决这个问题。或者可以理解为在继承类链中隔离了子类继承父类的某些特性,相当于要用父类的特性的时候,如果有Trait在就优先调用Trait中的成员。

Trait的声明

我们上面说到,声明Trait和声明class是相似的,只不过声明类需要使用class关键字,而声明Trait需要使用到trait关键字,类有的特性Trait基本都有,Trait支持final、static、和abstract等修饰词,所以Trait也就支持抽象方法的使用、类定义静态方法,当然也是可以定义属性。但是Trait无法像类一样使用new关键字进行实例化,因为Trait就是用来混入类中使用的,不能单独使用。所以我们前面也说了,Trait并不是用来代替类的,只是类的一种延伸。如果哪interface和Trait比较,Trait会有更多便捷的地方。接下来我们看看Trait是怎么声明和定义的。

注:使用Trait的需要在PHP5.4+

Trait声明代码如下:

<?php
trait TestTrait{
	public $a = 1;
	static $b = "HELLO";
	
	function methods1(){
		//todo
		
	}
	
	abstract public function methods2();//抽象方法
}

类(Class)声明的代码如下:

<?php
abstract class TestClass{
	public $a = 1;
	static $b = "HELLO";
	
	function methods1(){
		//todo
		
	}
	
	abstract public function methods2();//抽象方法
}

从上面代码的对比可以看出,除了trait和class关键字外,声明方式几乎一模一样。

Trait的使用

与类不同的是,Trait不能通过它自身来实例化对象,必须将其混入类中使用,相当于将Trait中的成员复制到类中,在应用类时就像使用自己的成员一样。其实就很像多模块手机,我们需要哪个模块或者模组,我们只需插入相关模块或者模组即可。如果要在类中使用Trait,需要通过use关键字将Trait混入类中。

<?php
trait TestTrait{
	public $a = 1;
	static $b = "HELLO";
	
	function methods1(){
		//todo
		echo "这是methods1<br>";
	}
	
	function methods2(){
		//todo
		echo "这是methods2<br>";
	}
}

class TestClass{
	use TestTrait;//将TestTrait混入类中
	
}

//调用方式

$o1 = new TestClass();
$o1->methods1();
$o1->methods2();//就跟使用自己的方法一样

执行结果如下:

【web开发】使用Trait解决PHP面向对象中类只支持单继承的限制_抽象方法

上面例子中,通过使用use关键字,在TestClass中混入了TestTrait中对成员。也可以通过use关键字一次混入多个Trait一起使用。通过逗号分隔(注意代码所说的符号一般都是英文半角的符号),在use声明列出多个Trait,可以都插入到一个类中,比如现在有2个Triat,分别命名为TestTrait1、TestTrait2.在TestClass中使用use关键字混入Trait。

<?php
class TestClass{
	use TestTrait1,TestTrait2;//将TestTrait1,TestTrait2混入类中
	
}

虽然在实际的使用中我们可以一次性混入多个Trait,但是需要注意的是,多个Trait之间同时使用难免会发生冲突,为了避免此情况发生,在PHP5.4就带入了相关的关键字语法"insteadof",这个关键的意思是,当发生冲突时使用insteadof关键字进行替换为指定的Trait的相关成员,具体使用代码如下:

<?php
trait TestTrait1{
	
	function methods1(){
		//todo
		echo "这是TestTrait1中的methods1<br>";
	}
}

trait TestTrait2{
	
	function methods1(){
		//todo
		echo "这是TestTrait2中的methods1<br>";
	}
}

class TestClass{
	use TestTrait1, TestTrait2{
		TestTrait1::methods1 insteadof TestTrait2;
	}//将TestTrait1,TestTrait2混入类中,如果发生冲突使用TestTrait1的methods1
	function methods(){
		//todo
		echo "这是methods<br>";
	}
}

//调用方式

$o1 = new TestClass();
$o1->methods1();

不仅可以在类中使用use关键字将Trait中的成员混入类中,也可以在Trait中使用use关键字将另外一个Trait中的成员混入进来,这样就形成了Trait之间的嵌套

<?php
trait TestTrait1{
	
	function methods1(){
		//todo
		echo "这是TestTrait1中的methods1<br>";
	}
}

trait TestTrait2{
	use TestTrait1;//TestTrait1混入TestTrait2中
	function methods2(){
		//todo
		echo "这是TestTrait2中的methods2<br>";
	}
}

class TestClass{
	use TestTrait2;//TestTrait2混入类中
	function methods(){
		//todo
		echo "这是类中的methods<br>";
	}
}

//调用方式

$o1 = new TestClass();
$o1->methods();
$o1->methods1();
$o1->methods2();

执行结果如下图:

【web开发】使用Trait解决PHP面向对象中类只支持单继承的限制_php_02

为了对使用的类施加强制的要求,Trait支持抽象方法的使用.如果在Trait中声明需要实现抽象方法,这样就能让使用它的类必须现实现它,这个跟继承一个抽象类是一样的,必须先实现类中的抽象方法.

<?php
trait TestTrait{
	
	abstract public function methods();
}

class TestClass{
	use TestTrait;//将TestTrait混入类中
	function methods(){
		//todo
		echo "这是methods<br>";
	}
}

//调用方式

$o1 = new TestClass();
$o1->methods();

总结

上面我们详细介绍了Trait比较常见的基本应用。使用Trait我们最应该了解的一下几点:

  1. Trait会覆盖调用类继承的父类方法
  2. 从基类继承的成员被Trait插入的成员所覆盖。优先顺序是:来自当前类的成员覆盖了Trait的方法,而Trait则覆盖了被继承的方法,其实就是有点就近原则的意思,先以自身的成员为主。
  3. Trait不能像类一样使用new直接实例化对象
  4. 在单个类中,使用use引入Trait,可以一次性引入多个Trait
  5. 单个Trait可有多个Trait组成,也就是可组成一个Trait的大集合,避免在类中使用use重复编写多余的代码,提升代码的可重用性。
  6. Trait支持使用诸如final,static,abstract等修饰关键字
  7. 可以使用insteadof及as操作符解决Trait之间的冲突
  8. 使用as语法还可以用来调整方法的访问控制

标签:web,use,继承,Trait,混入,使用,PHP,类中
From: https://blog.51cto.com/micai01/6503301

相关文章

  • 常见WebShell的流量特征
    常见WebShell的流量特征菜刀payload的特征:php:asp:<%evalrequest("caidao")%>asp.net:<%@PageLanguage="Jscript"%><%eval(Request.Item["caidao"],"unsafe");%>数据包流量特征:请求包中:ua头为百度请求体中有eval,base64等特征字符请求体中传......
  • vue3:vue+nginx+php进行服务端部署的配置(nginx/1.18.0 / vue@3.2.37)
    一,开发环境中的配置:1,前端:vue的vue.config.jsconst{defineConfig}=require('@vue/cli-service')module.exports=defineConfig({transpileDependencies:true,publicPath:process.env.NODE_ENV==="production"?"./":"/&qu......
  • CKS 考试题整理 (15)-镜像扫描ImagePolicyWebhook
    Contextcluster上设置了容器镜像扫描器,但尚未完全集成到cluster的配置中。完成后,容器镜像扫描器应扫描并拒绝易受攻击的镜像的使用。Task注意:你必须在cluster的master节点上完成整个考题,所有服务和文件都已被准备好并放置在该节点上。 给定一个目录/etc/kubernetes......
  • web worker进程和线程的区别,Chrome 中有哪些常⻅进程,如果我有⼀个耗时很⻓的同步计算
    进程(Process)和线程(Thread)都是操作系统中用于多任务处理的概念。简单地说,一个进程就是一个程序的执行空间,而一个线程则是在执行空间内独立运行的执行路径。区别:进程是系统分配资源的最小单位,线程是操作系统调度的最小单位。各个进程之间是独立的,各个线程之间共享一些资源。创......
  • eWebEditor从word复制粘贴公式
    ​如何做到ueditor批量上传word图片?1、前端引用代码<!DOCTYPE html PUBLIC "-//W3C//DTDXHTML1.0Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head>......
  • Qt+QtWebApp开发笔记(六):http服务器html实现静态相对路径调用第三方js文件
    前言  前面做了一些交互,网页是直接通过html对response进行返回的,这里QtWebApp与传统的web服务器不同,传统的web服务器可以调用同级目录相对路径或者绝对路径下的js,而QtWebApp的httpserver是response返回当前页面的问题,默认是无法调用的。  为了解决调用一些依赖的如echarts......
  • Socket及WebSocket(九)
    一、Socket套接字(Socket)是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程......
  • websocket 使用
     https://www.runoob.com/html/html5-websocket.html   ......
  • Linux下嵌入式Web服务器BOA和CGI编程开发
    https://blog.csdn.net/Ikaros_521/article/details/102610768一、环境搭建操作系统:Ubuntu12.04LTS(CentOS7类似0.0)boa下载地址(网址突然又挂了):http://www.boa.org/官方文档:http://www.boa.org/documentation/boa-2.htmlGitHub仓库:https://github.com/gpg/boa我是其他网站找......
  • 如何降低Vue.js项目中Webpack打包文件的大小?
    结论结论:vue中,直接引用文件,可以让打包文件最小。试验记录下面测试项目中引入一个Button组件的代价。基准工程大小:[raywill:shop]npmrunbuild>shop@build/Users/raywill/code/vue/shop>cross-envNODE_ENV=productionwebpack--progress--hide-modulesHash:d902d9dc5e......