PHP中trait使用方法详细介绍


Posted in PHP onMay 21, 2017

说通俗点,PHP中使用trait关键字是为了解决一个类既想集成基类的属性和方法,又想拥有别的基类的方法,而trait一般情况下是和use搭配使用的。

<?php
  trait Drive {
    public $carName = 'trait';
    public function driving() {
      echo "driving {$this->carName}\n";
    }
  }
  class Person {
    public function eat() {
      echo "eat\n";
    }
  }
  class Student extends Person {
    use Drive;
    public function study() {
      echo "study\n";
    }
  }
  $student = new Student();
  $student->study();
  $student->eat();
  $student->driving();

?>

输出结果如下:

study
eat
driving trait

上面的例子中,Student类通过继承Person,有了eat方法,通过组合Drive,有了driving方法和属性carName。

如果Trait、基类和本类中都存在某个同名的属性或者方法,最终会保留哪一个呢?

<?php 
  trait Drive {
    public function hello() {
      echo "hello drive\n";
    }
    public function driving() {
      echo "driving from drive\n";
    }
  }
  class Person {
    public function hello() {
      echo "hello person\n";
    }
    public function driving() {
      echo "driving from person\n";
    }
  }
  class Student extends Person {
    use Drive;
    public function hello() {
      echo "hello student\n";
    }
  }
  $student = new Student();
  $student->hello();
  $student->driving();
?>

输出结果如下:

hello student
driving from drive

因此得出结论:当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,而 trait 的方法又覆盖了基类中的方法。

如果要组合多个Trait,通过逗号分隔 Trait名称:

use Trait1, Trait2;

如果多个Trait中包含同名方法或者属性时,会怎样呢?答案是当组合的多个Trait包含同名属性或者方法时,需要明确声明解决冲突,否则会产生一个致命错误。

<?php
trait Trait1 {
  public function hello() {
    echo "Trait1::hello\n";
  }
  public function hi() {
    echo "Trait1::hi\n";
  }
}
trait Trait2 {
  public function hello() {
    echo "Trait2::hello\n";
  }
  public function hi() {
    echo "Trait2::hi\n";
  }
}
class Class1 {
  use Trait1, Trait2;
}
?>

输出结果如下:

PHP Fatal error:  Trait method hello has not been applied, because there are collisions with other trait methods on Class1 in ~/php54/trait_3.php on line 20

使用insteadof和as操作符来解决冲突,insteadof是使用某个方法替代另一个,而as是给方法取一个别名,具体用法请看代码:

<?php
trait Trait1 {
  public function hello() {
    echo "Trait1::hello\n";
  }
  public function hi() {
    echo "Trait1::hi\n";
  }
}
trait Trait2 {
  public function hello() {
    echo "Trait2::hello\n";
  }
  public function hi() {
    echo "Trait2::hi\n";
  }
}
class Class1 {
  use Trait1, Trait2 {
    Trait2::hello insteadof Trait1;
    Trait1::hi insteadof Trait2;
  }
}
class Class2 {
  use Trait1, Trait2 {
    Trait2::hello insteadof Trait1;
    Trait1::hi insteadof Trait2;
    Trait2::hi as hei;
    Trait1::hello as hehe;
  }
}
$Obj1 = new Class1();
$Obj1->hello();
$Obj1->hi();
echo "\n";
$Obj2 = new Class2();
$Obj2->hello();
$Obj2->hi();
$Obj2->hei();
$Obj2->hehe();
?>

输出结果如下:

Trait2::hello
Trait1::hi

Trait2::hello
Trait1::hi
Trait2::hi
Trait1::hello

as关键词还有另外一个用途,那就是修改方法的访问控制:

Trait 也能组合Trait,Trait中支持抽象方法、静态属性及静态方法,测试代码如下:

<?php
trait Hello {
  public function sayHello() {
    echo "Hello\n";
  }
}
trait World {
  use Hello;
  public function sayWorld() {
    echo "World\n";
  }
  abstract public function getWorld();
  public function inc() {
    static $c = 0;
    $c = $c + 1;
    echo "$c\n";
  }
  public static function doSomething() {
    echo "Doing something\n";
  }
}
class HelloWorld {
  use World;
  public function getWorld() {
    return 'get World';
  }
}
$Obj = new HelloWorld();
$Obj->sayHello();
$Obj->sayWorld();
echo $Obj->getWorld() . "\n";
HelloWorld::doSomething();
$Obj->inc();
$Obj->inc();
?>

输出结果如下:

Hello
World
get World
Doing something
1
2

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
使用TinyButStrong模板引擎来做WEB开发
Mar 16 PHP
PHP 批量删除数据的方法分析
Oct 30 PHP
PHP 读取和修改大文件的某行内容的代码
Oct 30 PHP
yiic命令时提示“php.exe”不是内部或外部命令的解决方法
Dec 18 PHP
php实现简易聊天室应用代码
Sep 23 PHP
php实现点击可刷新验证码
Nov 07 PHP
php安装ssh2扩展的方法【Linux平台】
Jul 20 PHP
PHP实现上传图片到 zimg 服务器
Oct 19 PHP
php注册系统和使用Xajax即时验证用户名是否被占用
Aug 31 PHP
PHPUnit测试私有属性和方法功能示例
Jun 12 PHP
PDO::setAttribute讲解
Jan 29 PHP
Laravel5.1 框架控制器基础用法实例分析
Jan 04 PHP
php写app接口并返回json数据的实例(分享)
May 20 #PHP
PHP实现json_decode不转义中文的方法
May 20 #PHP
Yii框架参数化查询中IN查询只能查询一个的解决方法
May 20 #PHP
Yii框架使用魔术方法实现跨文件调用功能示例
May 20 #PHP
Yii框架实现的验证码、登录及退出功能示例
May 20 #PHP
利用Laravel事件系统如何实现登录日志的记录详解
May 20 #PHP
Yii框架实现图片上传的方法详解
May 20 #PHP
You might like
比较全面的PHP数组的使用方法小结
2010/09/23 PHP
浏览器预览PHP文件时顶部出现空白影响布局分析原因及解决办法
2013/01/11 PHP
php实现水仙花数示例分享
2014/04/03 PHP
在PHP程序中使用Rust扩展的方法
2015/07/03 PHP
php计算年龄精准到年月日
2015/11/17 PHP
PHP实现文件上传下载实例
2016/10/18 PHP
javascript,jquery闭包概念分析
2010/06/19 Javascript
javascript full screen 全屏显示页面元素的方法
2013/09/27 Javascript
使用JSLint提高JS代码质量方法分享
2013/12/16 Javascript
JavaScript设计模式之适配器模式介绍
2014/12/28 Javascript
jquery中attr和prop的区别分析
2015/03/16 Javascript
解决jquery实现的radio重新选中的问题
2015/07/03 Javascript
JS判断输入的字符串是否是数字的方法(正则表达式)
2016/11/29 Javascript
深入理解javascript函数参数与闭包
2016/12/12 Javascript
Angular2学习笔记之数据绑定的示例代码
2018/01/03 Javascript
详解Vue-cli webpack移动端自动化构建rem问题
2018/04/07 Javascript
在Vue组件中获取全局的点击事件方法
2018/09/06 Javascript
微信小程序实现页面浮动导航
2019/01/28 Javascript
[jQuery] 事件和动画详解
2019/03/05 jQuery
PHP 502bad gateway原因及解决方案
2020/11/13 Javascript
[01:10:58]Spirit vs NB Supermajor小组赛 A组败者组决赛 BO3 第二场 6.2
2018/06/03 DOTA
python实现从文件中读取数据并绘制成 x y 轴图形的方法
2018/10/14 Python
Python 实现黑客帝国中的字符雨的示例代码
2020/02/20 Python
python matplotlib:plt.scatter() 大小和颜色参数详解
2020/04/14 Python
详解Python中@staticmethod和@classmethod区别及使用示例代码
2020/12/14 Python
迪卡侬中国官网:Decathlon中国
2020/08/10 全球购物
澳大利亚排名第一的露营和户外设备在线零售商:Outbax
2020/05/06 全球购物
TCP协议通讯的过程和步骤是什么
2015/10/18 面试题
函授毕业生的自我鉴定
2013/11/26 职场文书
《春笋》教学反思
2014/04/15 职场文书
敬老院院长事迹材料
2014/05/21 职场文书
邀请书格式范文
2015/02/02 职场文书
趣味运动会广播稿
2015/08/19 职场文书
《观察物体》教学反思
2016/02/17 职场文书
如何使用Tkinter进行窗口的管理与设置
2021/06/30 Python
css弧边选项卡的项目实践
2023/05/07 HTML / CSS