思考:php中继承是单继承,如果某个类有成员要被其他类使用,就需要称为其他类的父类才行,这样可能会导致继承链会长,合适吗?
引入:哦那个继承的角度触发,继承链可以解决问题,但是的确效率会打折扣,同时,如果某些功能是共性使用,但是并不符合继承条件(不属于同一类)
那么使用继承也有所违背面上对象规则,此时可以使用php提供的另外一种代码复用技术trait
trait代码复用【掌握】
定义:trait是为类似php的单继承语言而准备的一种代码复用机制,trait可以使得但继承语言为了复用而不得不继承的尴尬,让面向对象更加纯粹
1.trait是一种类似class的关键字
<?php
// 定义trait
trait show{
}
2.trait内部可以像类一样拥有成员属性(包含静态),成员方法(包含静态),但不能有常量
<?php
// 定义trait
trait show{
public $name;
protected $host; //允许定义,但实际不用
private $info;
public function show_time(){
echo $this->info;
}
protected function showhost(){ //允许定义,但实际不用
echo $this->name;
}
const pi=3.1415926; //错误 trait中不能有常量
}
3.trait是用来实现代码的复用的,不可以被实例化也不可以被继承
<?php
// 定义trait
trait show{
public $name;
protected $host; //允许定义,但实际不用
private $info;
public function show_time(){
echo $this->info;
}
protected function showhost(){ //允许定义,但实际不用
echo $this->name;
}
}
new show(); //trait 不允许被实例化
4.trait是用来将公共代码提供给其他类使用的,而类要使用trait的掐你是加载对应的trait
<?php
// 定义trait
trait Show{
public $name="d";
public function show_time(){
echo $this->name;
}
}
//类中加载trait
class add{
//加载:使用use关键字
use Show; //use 就表示将trait show中所有的东西拿到了当前类add中
}
//使用trait中的内容
$s=new add();
$s->show_time(); //show add类中自己没有show_time方法,但是因为使用了trait show 所以可用
5.一个类可以使用多个trait
<?php
// 定义trait
trait Show{
public $name="d";
public function show_time(){
echo $this->name;
}
}
trait get{
public $age=18;
public function get_age(){
echo $this->age;
}
}
//类中加载trait
class add{
//加载:使用use关键字
use Show; //use 就表示将trait show中所有的东西拿到了当前类add中
use get;
}
//使用trait中的内容
$s=new add();
$s->show_time(); //show add类中自己没有show_time方法,但是因为使用了trait show 所以可用
$s->get_age();
6.如果同时引入的多个trait中有同名方法,那么会产生冲突:解决冲突的方法是使用insteadof代替处理以及对被代替的方法使用别名
<?php
// 定义trait
trait show{
public $name="d";
public function show_time(){
echo $this->name;
}
}
trait get{
public $age=18;
public function show_time(){
echo $this->age;
}
}
//类中加载trait
class add{
// use get,show; //错误 2个trait存在同名的方法
// 方案1 使用其中一个同名方法
use get,show{
// 意思 使用show中的show_time 代替get中的show_time,并且会被覆盖无法使用
show::show_time insteadOf get;
// 方案2 给get中的show_time取一个别名 就可以使用了。
get::show_time as show_insteadostime;
}
}
$s=new add();
$s->show_time(); //输出的是d 而不是18 代替成功
$s->show_insteadostime(); //显示18
7.同名覆盖问题:如果类中有与引入的trait同名成员,会有不同处理
属性:不允许重名,即类中不允许定于与trait中同名的成员属性(静态属性也一样)
方法:类覆盖trait
<?php
// 定义trait
trait show{
public $name="d";
public function show_time(){
echo $this->name;
}
}
trait get{
public $age=18;
public function show_time(){
echo $this->age;
}
}
//类中加载trait
class add{
// use get,show; //错误 2个trait存在同名的方法
// 方案1 使用其中一个同名方法
use get,show{
// 意思 使用show中的show_time 代替get中的show_time,并且会被覆盖无法使用
show::show_time insteadOf get;
// 方案2 给get中的show_time取一个别名 就可以使用了。
get::show_time as show_insteadostime;
}
}
$s=new add();
$s->show_time(); //输出的是d 而不是18 代替成功
$s->show_insteadostime(); //显示18
8.继承覆盖问题:如果类中在使用trait的同时,也是继承自父类,而trait中与父类中有同名方法,那么trait中将覆盖父类同名方法,如果要访问父类方法,
可以在trait同名方法中使用parent关键字访问父类同名方法。
<?php
// 代码复用
trait posen{
public $name="杜伟";
public $age=31;
public function show(){
// 如果想用父类中的方法
parent::show();
echo $this->name.$this->age;
}
}
// 父类
class human{
public function show(){
echo 'human::show<hr>';
}
}
// 定义子类
class son extends human{
use posen;
}
// 实例化
$s=new son();
$s->show(); //显示的是杜伟 31 trait中的方法会覆盖继承中父类的方法
9.另外,trait自己不能访问,只是用来给其他类提供代码复用的,因此允许类在使用trait时更高里面方法的访问控制权。在as 之后,使用目标访问修饰限定符。
<?php
// 代码复用
trait posen{
private function show(){
echo '你看到我了';
}
}
class son{
use posen{
//因为我只是引用了一个show,如果是两个的话 需要具体的体现是哪个 posen::show(这个)
show as public pshow;
//注意 as是用来起别名的,虽然没有同名show 但是系统认为已经存在,并且改变trait中show的访问权限为public 变成了一个新的方法,原来的方法不动。
}
}
// 实例化
$s=new son();
$s->pshow(); //调用别名方法
10.trait中可以使用抽象方法,用来规范使用类必须实现对应抽象方法,使用了欸要么为抽象类,要么就必须实现抽象方法
<?php
// 代码复用
trait posen{
abstract public function add(); //trait 定义抽象方法
}
// 第一种方式
abstract class man{
use posen; //抽象类可以不实现抽象方法
}
// 第二种
class son{
use posen;
public function add(){
echo '实现了trait中的抽象方法'; //实现抽象方法
}
}
总结:
1.trait的hi一种类似class结构关键字,trait不能被实例化,可以拥有所有类成员结构
2.trait是用来实现代码复用的,为其他类提供公共代码(方法),其他类如果使用trait用use关键字引入
3.在了类中use是具体trait就相当于将trait内部的所有代码在类中写了一遍
4.一个类中可以有多个trait,但是要注意同名问题
同名方法可以使用insteadof来实现代替:一个trait中的同名方法代替另外一个,类就访问替代的那个
同名方法可以在被替代之后使用as制作方法使用as制作方法别名:类就可以拥有两个方法
5.类中在引入trait后,要注意与trait中的同名成员问题
同名属性:不允许
同名方法:允许,类中的方法会覆盖trait中的方法
6.如果在使用trait的同时也继承其他类,那么trait中出现的同名方法会覆盖基类的同名方法
7.类在使用trait时可以修改trait方法的控制级别,更严或这更宽松都可以,注意修改控制级别时使用的时别名机制,一定要改成别名:trait名::方法名 as 访问修饰限定符 别名;
8.trait中可以使用抽象方法,那么使用该trait的类就必须本身为抽象类或者将抽象方法实现
9.trait使用机制
有公共代码要实现(方法),而这些方法可能在很多类中会用到
公共代码不是属于某一类事务特有,而是很多事务都有(不符合继承)
以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家,需要
PHP进阶架构师>>>视频、面试文档免费获取docs.qq.com或 者关注咱们下面的知乎专栏
PHP大神进阶zhuanlan.zhihu.com来源:https://www.cnblogs.com/xiaowie/p/12303583.html