PHP中的类不支持多继承,但是提供了trait语法类解决单继承没法提供的多层代码复用问题。
要点:
1 Trait 不能通过它自身来实例化,但可以在类中使用,也可以通过静态调用使用trait中方法和属性。
<?php
trait T{
public function t_method(){
echo "this is t_method<br>";
}
}
class C{
//在类中使用trait
use T;
public function c_method(){
echo "this is c_method<br>";
}
}
$cls= new C();
$cls->t_method();
//通过类调用
$cls->c_method();
//静态调用
T::t_method();
?>
输出结果:
this is t_method
this is c_method
this is t_method
2 在类中使用trait,如果出现类的函数或属性于trait的函数或属性同名,就回会发生覆盖---》当前类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了当前类父类中的方法。
<?php
trait T{
public function sameWithBase(){
echo "this is trait's sameWithBase()<br>";
}
public function commonMethod(){
echo "this is trait's commonMethod()<br>";
}
}
class base{
public function sameWithBase(){
echo "this is base's sameWithBase()<br>";
}
public function commonMethod(){
echo "this is base's commonMethod()<br>";
}
}
class C extends base{
use T;
public function commonMethod(){
echo "this is class's commonMethod()<br>";
}
}
$cls=new C();
//trait方法覆盖父类方法
$cls->sameWithBase();
//当前类方法覆盖trait方法
$cls->commonMethod();?>
输出结果
this is trait's sameWithBase()
this is class's commonMethod()
3 可以在同一个类中使用多个Trait,如果出现多个Trait中有函数或属性同名的情况,运行时就会报错。有两种方式解决,A方式:需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个 ,B方式:使用as 操作符可以将其中一个冲突的方法以另一个名称来引入。
<?php
trait T1{
public function sameName1(){
echo "this is T1's sameName1()<br>";
}
public function sameName2(){
echo "this is T1's sameName2()<br>";
}
}
trait T2{
public function sameName1(){
echo "this is T2's sameName1()<br>";
}
public function sameName2(){
echo "this is T2's sameName2()<br>";
}
}
class C{
use T1,T2{
//如果每个方法的作用都不同,那C使用T1,T2后,按理将会拥有4个方法。
//但是因为有同名方法,如果C只用sameName1()和sameName2()两个函数名,那C只能有拥有两个方法,
//而且调用sameName1()和sameName2()时程序并不知道是T1,还是T2中的,所以,重名的方法必须
//全部指定具体使用的是哪一个!
//需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。
T1::sameName1 insteadof T2;
T2::sameName2 insteadof T1;
//insteadof 必须有name1和name2,否则会报错
//as 为可选
//B方式在使用时给同名的方法或属性重命名
T2::sameName2 as rename;
T2::sameName1 as rename1;
}
}
$cls=new C();
$cls->sameName1();
$cls->sameName2();
$cls->rename();
$cls->rename1();
?>
输出结果
this is T1's sameName1()
this is T1's sameName2()
this is T2's sameName2()
this is T2's sameName1()
4 在使用时可以修改的访问属性。
<?php
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
}
// 修改 sayHello 的访问控制
class MyClass1 {
use HelloWorld { sayHello as protected; }
}
// 给方法一个改变了访问控制的别名
// 原版 sayHello 的访问控制则没有发生变化
class MyClass2 {
use HelloWorld { sayHello as private myPrivateHello; }
}
?>
5 可以用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();
?>
输出结果
Hello World!
6 trait中可以有属性,静态方法,抽象方法。