博客列表 >PHP基础-trait使用细节/trait扩展接口

PHP基础-trait使用细节/trait扩展接口

岂几岂几
岂几岂几原创
2020年05月03日 20:06:45694浏览

1. trait组合的同名方法的命名冲突解决方案

  1. 使用同名方法之一覆盖另一个同名方法
  2. 为被覆盖的同名方法起别名
  1. trait Trait1
  2. {
  3. /* 同名属性没办法处理 */
  4. // public static $prop1 = 'prop_of_trait1';
  5. public static function func1()
  6. {
  7. return sprintf('%s中定义的%s方法', __TRAIT__, __METHOD__);
  8. }
  9. }
  10. trait Trait2
  11. {
  12. // public static $prop1 = 'prop_of_trait2';
  13. public static function func1()
  14. {
  15. return sprintf('%s中定义的%s方法', __TRAIT__, __METHOD__);
  16. }
  17. }
  18. class Demo1
  19. {
  20. use Trait1, Trait2 {
  21. // 使用Trait1::func1()方法覆盖Trait2中的同名方法
  22. Trait1::func1 insteadof Trait2;
  23. // 给Trait1::func2()起别名
  24. Trait2::func1 as public t2_func1;
  25. }
  26. }
  27. echobr(Demo1::func1());
  28. echobr(Demo1::t2_func1());
  29. /*
  30. result:
  31. Trait1中定义的Trait1::func1方法
  32. Trait2中定义的Trait2::func1方法
  33. */

2. 改变trait成员的访问控制

  • 同样使用as关键字
  1. trait Trait3
  2. {
  3. public static function func1()
  4. {
  5. return sprintf('%s中定义的%s方法', __TRAIT__, __METHOD__);
  6. }
  7. }
  8. class Demo2
  9. {
  10. use Trait3 {
  11. Trait3::func1 as private tfunc1;
  12. }
  13. public static function func1()
  14. {
  15. // 内部方法可以访问私有方法tfun1
  16. return self::tfunc1();
  17. }
  18. }
  19. echobr(Demo2::func1());
  20. // 外部访问已被改变为私有的成员方法tfunc1, 将会报错
  21. echobr(Demo2::tfunc1());
  22. /*
  23. result:
  24. Trait3中定义的Trait3::func1方法
  25. Fatal error: Uncaught Error: Call to private method Demo2::tfunc1() from context '' in D:\phpstudy_pro\WWW\php11\PHP\0430\homework.php:73 Stack trace: #0 {main} thrown in D:\phpstudy_pro\WWW\php11\PHP\0430\homework.php on line 73
  26. */

3. trait 实现接口方法的优缺点

3.1 trait实现接口方法的优点

  1. 减少接口实现代码冗余: 假设不使用trait实现接口方法, 多个类扩展某个接口, 必须在这些类内部实现该接口的方法, 这会造成实现接口的代码冗余.
  2. 借用trait实现多继承: 假设两个(或多个)接口已经有对应的实现类, PHP的单继承限制, 没有办法同时继承这两个(或多个)实现类. 但使用trait实现接口, 就能实现多继承.

    3.2 trait实现接口方法的缺点

    想不出来…

4. trait, 接口和抽象类联合编程

  1. // 数据库操作接口
  2. interface IDbOpera
  3. {
  4. public function getData($id = null);
  5. public function addData($data);
  6. public function saveData($id, $data);
  7. public function deleteData($id);
  8. }
  9. // 模拟员工信息表的数据库操作, 实现IDbOpera接口的抽象方法
  10. trait TDbOpera
  11. {
  12. private $datas = [
  13. ['id' => 1, 'name' => '张三', 'sex' => 'male', 'age' => 25, 'salary' => 9999],
  14. ['id' => 2, 'name' => '李四', 'sex' => 'female', 'age' => 30, 'salary' => 8888],
  15. ['id' => 3, 'name' => '王五', 'sex' => 'male', 'age' => 35, 'salary' => 7777],
  16. ['id' => 4, 'name' => '赵六', 'sex' => 'male', 'age' => 40, 'salary' => 11111],
  17. ['id' => 5, 'name' => '钱七', 'sex' => 'female', 'age' => 45, 'salary' => 9797],
  18. ['id' => 6, 'name' => '吴八', 'sex' => 'male', 'age' => 28, 'salary' => 7979],
  19. ['id' => 7, 'name' => '陈九', 'sex' => 'male', 'age' => 37, 'salary' => 8866],
  20. ];
  21. public function getData($id = null)
  22. {
  23. if ($id) {
  24. return $this->datas[$id];
  25. }
  26. return $this->datas;
  27. }
  28. public function addData($data)
  29. {
  30. array_push($this->datas, $data);
  31. $keys = array_keys($this->datas);
  32. $key = end($keys);
  33. $this->datas[$key]['id'] = $key + 1;
  34. }
  35. public function saveData($id, $data)
  36. {
  37. $this->datas[$id - 1] = $data;
  38. }
  39. public function deleteData($id)
  40. {
  41. unset($this->datas[$id - 1]);
  42. }
  43. }
  44. // 抽象类定义员工管理的操作
  45. abstract class AbstractEmployeeManage implements IDbOpera
  46. {
  47. use TDbOpera;
  48. // 雇佣新员工
  49. abstract function addEmployee($employee);
  50. // 解雇
  51. abstract function fireEmployee($id);
  52. // 获取员工
  53. abstract function getEmployee($id = null);
  54. // 修改员工信息
  55. abstract function updateEmployee($id, $employee);
  56. }
  57. // 员工管理实现类
  58. class EmployeeManage extends AbstractEmployeeManage
  59. {
  60. // 雇佣新员工
  61. function addEmployee($employee)
  62. {
  63. $this->addData($employee);
  64. echobr('新员工新增成功');
  65. }
  66. // 解雇
  67. function fireEmployee($id)
  68. {
  69. $this->deleteData($id);
  70. echobr('该员工已成功解雇');
  71. }
  72. // 获取员工
  73. function getEmployee($id = null)
  74. {
  75. return $this->getData($id);
  76. }
  77. // 修改员工信息
  78. function updateEmployee($id, $employee)
  79. {
  80. $this->saveData($id, $employee);
  81. echobr('员工信息修改成功');
  82. }
  83. function showEmployee($employee)
  84. {
  85. if (!isset($employee['id'])) {
  86. foreach ($employee as $emp) {
  87. // printfpre($emp);
  88. $sex = ($emp['sex'] === 'male') ? '男' : '女';
  89. echobr("id: {$emp['id']}, 姓名: {$emp['name']}, 性别: {$sex}, 年龄: {$emp['age']}, 月薪: {$emp['salary']}.");
  90. }
  91. } else {
  92. $sex = $emp['sex'] === 'male' ? '男' : '女';
  93. echobr("id: {$employee['id']}, 姓名: {$employee['name']}, 性别: {$sex}, 年龄: {$employee['age']}, 月薪: {$employee['salary']}.");
  94. }
  95. }
  96. }
  97. // 客户端调用
  98. $employeeManage = new EmployeeManage;
  99. $newEmployee = ['name' => '小明', 'sex' => 'female', 'age' => 23, 'salary' => 5000];
  100. /* 新增员工 */
  101. $employeeManage->addEmployee($newEmployee);
  102. /*
  103. result: 新员工新增成功
  104. */
  105. echobr();
  106. /* 获取所有员工信息 */
  107. echobr('员工信息列表');
  108. $employeeManage->showEmployee($employeeManage->getEmployee());
  109. /*
  110. result:
  111. 员工信息列表
  112. id: 1, 姓名: 张三, 性别: 男, 年龄: 25, 月薪: 9999.
  113. id: 2, 姓名: 李四, 性别: 女, 年龄: 30, 月薪: 8888.
  114. id: 3, 姓名: 王五, 性别: 男, 年龄: 35, 月薪: 7777.
  115. id: 4, 姓名: 赵六, 性别: 男, 年龄: 40, 月薪: 11111.
  116. id: 5, 姓名: 钱七, 性别: 女, 年龄: 45, 月薪: 9797.
  117. id: 6, 姓名: 吴八, 性别: 男, 年龄: 28, 月薪: 7979.
  118. id: 7, 姓名: 陈九, 性别: 男, 年龄: 37, 月薪: 8866.
  119. id: 8, 姓名: 小明, 性别: 女, 年龄: 23, 月薪: 5000.
  120. */
  121. echobr();
  122. /* 获取王五的信息 */
  123. echobr('王五的员工信息');
  124. $emp = $employeeManage->getEmployee(2);
  125. $employeeManage->showEmployee($emp);
  126. /*
  127. result:
  128. 王五的员工信息
  129. id: 3, 姓名: 王五, 性别: 女, 年龄: 35, 月薪: 7777.
  130. */
  131. /* 王五涨工资了 */
  132. $emp['salary'] = 8848;
  133. $employeeManage->updateEmployee($emp['id'], $emp);
  134. /*
  135. result: 员工信息修改成功
  136. */
  137. /* 钱七被解雇了 */
  138. $employeeManage->fireEmployee(5);
  139. echobr('员工信息表');
  140. $employeeManage->showEmployee($employeeManage->getEmployee());
  141. /*
  142. result:
  143. 该员工已成功解雇
  144. 员工信息表
  145. id: 1, 姓名: 张三, 性别: 男, 年龄: 25, 月薪: 9999.
  146. id: 2, 姓名: 李四, 性别: 女, 年龄: 30, 月薪: 8888.
  147. id: 3, 姓名: 王五, 性别: 男, 年龄: 35, 月薪: 8848.
  148. id: 4, 姓名: 赵六, 性别: 男, 年龄: 40, 月薪: 11111.
  149. id: 6, 姓名: 吴八, 性别: 男, 年龄: 28, 月薪: 7979.
  150. id: 7, 姓名: 陈九, 性别: 男, 年龄: 37, 月薪: 8866.
  151. id: 8, 姓名: 小明, 性别: 女, 年龄: 23, 月薪: 5000.
  152. */

学习心得

  • 当使用的多个trait有同名方法是, 配合使用insteadofas关键字实现triat中同名方法均可使用.
  • trait实现接口的优缺点
    优点: 可以实现代码复用; 借trai实现多继承. 具体解释见”#3 trait 实现接口方法的优缺点”.
    缺点: 想不出来, 需要老师解惑.
  • trait, 接口和抽象类联合编程思路: 接口定义操作方法; trait实现接口定义的方法; 抽象类继承接口, 并使用trait实现接口定义的方法, 同时声明给客户端使用的抽象方法. 工作类实现给客户端使用的抽象方法, 其中用到trait实现的接口定义的方法.
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议