Blogger Information
Blog 57
fans 3
comment 0
visits 60340
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
PHP基础-trait使用细节/trait扩展接口
岂几岂几
Original
695 people have browsed it

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实现的接口定义的方法.
Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:缺点就是让代码的复杂度提高了, 但凡事没有二全其美的
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!