- php中继承是单继承,如果某个类有成员要被其他类使用,就需要称为其他类的父类才行,这样可能会导致继承链会长,合适吗?
引入:继承的角度出发,继承链可以解决问题,但是的确效率会打折扣,同时,如果某些功能是共性使用,但是并不符合(不属于同一类)继承条件,那么使用继承也有所违背面上对象规则,此时可以使用php提供的另外一种代码复用技术trait
一:代码复用
二:在继承上下文中的应用
三:实现功能扩展
四:在trait组合中命名冲突的解决方案
五:trait和interface的组合
1.代码复用
定义:trait是为类似php的单继承语言而准备的一种代码复用机制,trait可以避免继承语言为了复用而不得不继承的尴尬,让面向对象更加纯粹
1-1、trait是一种类似class的关键字
定义trait
trait show{
}
1-2、trait内部可以像类一样拥有成员属性(包含静态),成员方法(包含静态),但不能有常量
示例:
trait uSername //定义trait
{
public function show() //定义一个公用的方法
{
return '姓名:'.$this->username.'|国家:'.$this->nation.'|电话:'.$this->mobile;
//返回一段用户信息
}
public static function show1() //定义一个show1静态方法
{
printf('<pre>%s</pre>',print_r(get_class_vars(__CLASS__),true));
//打印当前类返回的数组get_class_vars
}
}
class User //定义一个User类
{
use uSername; //调用trait
protected $username ='曹操'; //为隐私属性赋值
public $nation ='魏国'; //为公用属性赋值
private $mobile ='13666666666';//为私有属性赋值
}
echo (new User)->show(); //实例化User调用trait
class User1 //定义一个User1类
{
use uSername; //调用trait
public $username ='刘备'; //为公用属性赋值
private $nation ='蜀国'; //为私有属性赋值
protected $mobile ='13555555555'; //为隐私属性赋值
}
echo (new User1)->show(); //实例化User调用trait
User::show1(); //使用静态实例化调用trait中的show1方法
User1::show1(); //使用静态实例化调用trait中的show1方法
示例图
![](https://img.haomeiwen.com/i20572511/9fd781b0523256e7.png)
2:在继承上下文中的应用
在实例中创建了trait及抽象类和子类,知道了通过实例化子类对程序的执行顺序。
示例:
trait aTtribute 创建trait
{
public static function show() 创建一个静态的show方法
{
echo '我是trait->show<br>';
return Attribute1::show(); 返回一条字符串
}
}
abstract class Attribute1 抽象类不可以被实例化
{
use aTtribute; 调用trait
public static function show() //抽象类中创建一个静态的show方法
{
返回trait的show方法
return '我是父类show<br>';
}
}
class Attribute2 extends Attribute1 //创建Attribute的子类
{
use aTtribute; //调用trait
public static function show() //创建一个静态的show方法
{
echo '我是子类show<br>';
return aTtribute::show(); //返回抽象类的的show方法
}
}
echo Attribute2::show(); //输出Attribute2子类的show()方法
//子类同名成员优先大于父类同名成员
//如果子类、父类、trait中存在同名方法的时候,而trait在子类中调用,先调用子类->在调用trait->父类
![](https://img.haomeiwen.com/i20572511/f646e814110c6172.png)
3:实现功能扩展
示例:
trait tDemo
{
//1.打印所有属性
public function getProps()
{
printf('<pre>%s</pre>',print_r(get_class_vars(__CLASS__),true));
}
}
trait tDemo1
{
//2.打印所有方法
public function getMethost()
{
printf('<pre>%s</pre>',print_r(get_class_methods(__CLASS__),true));
}
//__CLASS__:返回当前类的名称字符串
//self:返回当前类的引用
}
trait tDemo2
{
use tDemo1,tDemo;
}
class Users
{
use tDemo2;
public $name ='刘备';
public $nation ='蜀国';
public function show()
{
return $this->name.':'.$this->nation;
}
//扩展这个类的功能
//添加二个公共方法
}
echo (new Users)->show();
echo (new Users)->getProps();
echo (new Users)->getMethost();
示例图
![](https://img.haomeiwen.com/i20572511/62f6fdf47e98d501.png)
4:在trait组合中命名冲突的解决方案
- 在trait中有重名的方法,可以使用insteadOf替换将重名的的方法重命名。
- 格式
trait名称::重名的方法 as 新的命名;
trait名称::重名的方法 insteadOf替换 trait名称::重名的方法;
示例:
trait tDemo
{
public static $car = '汽车';
public static function show() //定义的了静态show方法`
{
return self::$car;
}
}
trait tDemo1
{
public static $train = '火车';
public static function show() //定义的了静态show方法
{
return self::$train;
}
}
trait tDemo2
{
use tDemo, tDemo1 {
tDemo1::show as toshow;
//给tDemo1::show()起个别名: toshow
tDemo::show insteadOf tDemo1;
// show方法冲突时使用tDemo1类的show方法而不使用tDemo类的show方法
}
}
class Work
{
use tDemo2;
}
echo (new Work)->show();
echo (new Work)->toshow();
![](https://img.haomeiwen.com/i20572511/57123eae2ba5fd2e.png)
5:trait和interface的组合
-
通过trait实现interface接口的方法,然后实例化
示例
interface iDemo //定义一个接口
{
public static function index();
}
trait tDemo //定义一个trait
{
public static function index() //在tDemo中定义一个接口方法
{
return '我是在trait中的!';
}
}
class Hello implements iDemo //定义一个类实现iDemo
{
use tDemo; //类中应用trait
}
echo (new Hello)->index();
//本实例定义一个接口,然后在trait中实现接口方法,然后实例化
示例图
![](https://img.haomeiwen.com/i20572511/85106ddda9c92f7b.png)
网友评论