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 相关文章推荐
一次编写,随处运行
Oct 09 PHP
php5 pdo新改动加载注意事项
Sep 11 PHP
PHP5+UTF8多文件上传类
Oct 17 PHP
PHP 数据库树的遍历方法
Feb 06 PHP
php foreach 使用&amp;(与运算符)引用赋值要注意的问题
Feb 16 PHP
apache配置虚拟主机的方法详解
Jun 17 PHP
一个经典的PHP文件上传类分享
Nov 18 PHP
PHP 读取文本文件内容并分页显示
Jan 02 PHP
Laravel5.0+框架邮件发送功能实现方法图文与实例详解
Apr 23 PHP
php用户名的密码加密更安全的方法
Jun 21 PHP
thinkphp5 模型实例化获得数据对象的教程
Oct 18 PHP
PHP解决高并发的优化方案实例
Dec 10 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实现的功能是显示8条基色色带
2006/10/09 PHP
Yii PHP Framework实用入门教程(详细介绍)
2013/06/18 PHP
完美解决PHP中的Cannot modify header information 问题
2013/08/12 PHP
PHP图片处理之使用imagecopyresampled函数裁剪图片例子
2014/11/19 PHP
thinkphp缓存技术详解
2014/12/09 PHP
PHP文件操作方法汇总
2015/07/01 PHP
新浪的图片新闻效果
2007/01/13 Javascript
JavaScript-世界上误解最深的语言分析
2007/08/12 Javascript
jQuery EasyUI 的EasyLoader功能介绍
2010/09/12 Javascript
浅谈JavaScript 框架分类
2014/11/10 Javascript
使用jquery制作弹出框效果
2015/04/03 Javascript
js实现跨域的方法实例详解
2015/06/24 Javascript
基于BootStrap Metronic开发框架经验小结【六】对话框及提示框的处理和优化
2016/05/12 Javascript
JS实现兼容各种浏览器的获取选择文本的方法【测试可用】
2016/06/21 Javascript
浅谈AngularJS中ng-class的使用方法
2016/11/11 Javascript
vue组件间的参数传递实例详解
2019/04/26 Javascript
vue实现匀速轮播效果
2020/06/29 Javascript
基于vue.js仿淘宝收货地址并设置默认地址的案例分析
2020/08/20 Javascript
Python 查看文件的编码格式方法
2017/12/21 Python
Python爬取数据并实现可视化代码解析
2020/08/12 Python
Python修改DBF文件指定列
2020/12/19 Python
html+css实现自定义图片上传按钮功能
2019/09/04 HTML / CSS
HTML5中indexedDB 数据库的使用实例
2017/05/11 HTML / CSS
加拿大在线隐形眼镜专家:PerfectLens.ca
2016/11/19 全球购物
荷兰的时尚市场:To Be Dressed
2019/05/06 全球购物
澳大利亚运动鞋商店:Platypus Shoes
2019/09/27 全球购物
德国大型箱包和皮具商店:Koffer
2019/10/01 全球购物
高中毕业自我鉴定
2013/12/19 职场文书
销售口号大全
2014/06/11 职场文书
向国旗敬礼学生寄语大全
2014/09/30 职场文书
2014年组织部工作总结
2014/11/14 职场文书
2016年过年放假安排通知
2015/08/18 职场文书
给原生html中添加水印遮罩层的实现示例
2021/04/02 Javascript
javascript的var与let,const之间的区别详解
2022/02/18 Javascript
Apache SeaTunnel实现 非CDC数据抽取
2022/05/20 Servers
Nginx 配置 HTTPS的详细过程
2022/05/30 Servers