首页 > 技术分享 > 原生PHP
收藏

PHP中trait使用方法,PHP导入多个类的方法,PHP8.2中trait的新特性

05/23 17:14
大潇博客 原创文章,转载请标明出处

trait是一种代码复用机制。


当一个类需要用到另一个类或多个类时,常用的方法有继承、require引入文件并实例化类等。但PHP只支持单继承,require引入并实例化类后,也只能访问其中的public方法。


PHP还提供一种方式,通过trait类,完全将其它类导入到当前类中,导入后可视为当前类的一部分,区别是不同类中,可能存在相同名称的方法,此时可通过设置别名、设置优先级的方法来控制访问。


Trait类与当前使用类、继承的父类之间的调用优先级顺序如下:

当前使用类>Trait类>继承的父类。当存在同名方法时,会根据优先级覆盖掉同名的类。


trait使用示例:

//trait 是一种代码复用机制

//定义可复用类

trait loggable{

public function logs($message){

      echo "Logging:".$message;

}

}

class User{

//使用use,引用已定义的可复用类

use loggable;

public function save(){

      //通过use引用loggable类后,可通过 $this 直接使用loggable类中的方法

      $this->logs("日志");

}

}

$user=new User();

$user->save();  //Logging:日志


insteadod关键字:

当引用的多个类中,包含相同的方法名时,可通过 insteadof 关键字设置优先级

//trait 是一种代码复用机制

//定义可复用类 TraitA

trait TraitA{

public function foo(){

      echo "TraitA's foo method";

}

}

//定义可复用类 TraitB

trait TraitB{

public function foo(){

      echo "TraitB's foo method";

}

}

class MyClass{

//引用的 TraitA 和 TraitB 同时存在 foo 方法

//若不处理,程序会抛出致命错误 Fatal error: Trait method TraitB::foo has not been applied as MyClass::foo, because of collision with TraitA::foo

use TraitA,TraitB{

      //使用 insteadof 关键字,可以指定优先使用哪个trait中的 foo 方法

      //TraitA::foo insteadof TraitB;

      TraitB::foo insteadof TraitA;  //TraitB优先级高于TraitA

}

}

$myclass=new MyClass();

$myclass->foo();  //TraitB's foo method


as关键字:

当引用的多个类中,包含相同的方法名时,可通过 as 关键字设置别名,然后在类中重写重名的方法,实现每个方法都能正常使用

//trait 是一种代码复用机制

//定义可复用类 TraitA 

trait TraitA{

//PHP8.2新特性,允许在trait中定义常量

//PHP版本低于8.2,会抛出致命错误,非8.2环境请注释下面使用const定义的常量

const FOO = 'foo';

private const BAR = 'bar';

final const VIM = 'vim';

final protected const RCO = 'rco';

public function foo(){

      echo "TraitA's foo method".",";

}

}

//定义可复用类 TraitB

trait TraitB{

public function foo(){

      echo "TraitB's foo method".",";

}

}


class MyClass{

//引用的 TraitA 和 TraitB 同时存在 foo 方法,若不处理,程序会抛出致命错误:Trait method TraitB::foo has not been applied..

use TraitA, TraitB{

      //使用 as 关键字起别名

      TraitA::foo as public TraitAFoo; //新的方法名为 TraitAFoo

      TraitB::foo as protected TraitBfoo;

}

//写法二:可分开引用

//use TraitA{   TraitA::foo as public TraitAFoo;   }

//use TraitB{   TraitB::foo as public TraitBfoo;   }


//在没有使用insteadof关键字设置优先级时,必须重写 foo 方法,否则抛致命错误 

//Fatal error: Trait method TraitB::foo has not been applied as MyClass::foo, because of collision with TraitA::foo

public function foo(){

      //可在此调用 TraitA 或 TraitB 中的 foo 方法(可看做设置默认foo方法)

      //$this->TraitAFoo();

      $this->TraitBFoo();

}

}


$myclass=new MyClass();

$myclass->TraitAFoo();  //TraitA's foo method,

$myclass->foo();  //TraitB's foo method,

//PHP8.2新特性,trait中定义常量

echo $myclass::FOO;  //foo

echo ",";

echo $myclass::VIM;  //vim


在定义trait类时,即使没有继承任何类,也可以在trait类的方法中通过“parent::父方法名”,提前申明要使用的父类方法

在use引用这个trait类时,必须有继承,且继承的父类要包含已经在trait类中声明过的,要使用的父类方法(parent::父方法名)

由此可看出,use引用trait类后,可视作当前类的一部分

//定义基础类 Base

class Base{

public function sayHello(){

      echo "Hello";

}

}

//定义重复使用类 Another

trait Another{

protected function sayHello(){

      //此处虽没有直接继承,但使用use引用的类有继承

      //可理解为:使用 use 导入 Another 后,即可把它看做当前类的一部分

      parent::sayHello();   //注意:这里提前声明要使用父类的sayHello方法

      echo " World";

}

}

//定义重复使用类 Other

trait Other{

private function sayHello(){

      echo "Hello World, Hello Everyone";

}

}


//定义要使用的类 Main ,并继承基础类 Base

class Main extends Base{

//引用 Another 和 Other 两个类(多继承)

//引用的两个类中,都包含 sayHello 方法,使用 as 关键字起别名

use Another,Other{

      Another::sayHello as public AnotherHello;

      Other::sayHello as public OtherHello;

}

//重写 sayHello 方法(必须)

public function sayHello(){

      $this->OtherHello();

}

}

$main = new Main();

$main->AnotherHello();  //Hello World

echo ",";

$main->sayHello();  //Hello World, Hello Everyone


打赏

阅读排行

大家都在搜

博客维护不易,感谢你的肯定
扫码打赏,建议金额1-10元
  • 15601023311