经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » PHP » 查看文章
PHP中的“重载”是个啥?
来源:cnblogs  作者:硬核项目经理  时间:2021/2/18 15:43:33  对本文有异议

很多面试官在面试的时候都会问一些面向对象的问题,面向对象的三大特性中,多态最主要的实现方式就是方法的重载和重写。但是在PHP中,只有重写,并没有完全的重载能力的实现。

重写,子类重写父类方法。

  1. // 重写
  2. class A
  3. {
  4. public function test($a)
  5. {
  6. echo 'This is A:' . $a, PHP_EOL;
  7. }
  8. }
  9. class childA extends A
  10. {
  11. public function test($a)
  12. {
  13. echo 'This is A child:' . $a, PHP_EOL;
  14. }
  15. }
  16. $ca = new childA();
  17. $ca->test(1);

这个在PHP中是没有任何问题的,子类可以重写父类的方法。当实例化子类的时候,调用的就是子类实现的重写的方法。

重载,相同方法名但参数数量或者类型不同。

  1. class A{
  2. function foo($a){
  3. echo $a;
  4. }
  5. // Fatal error: Cannot redeclare A::foo()
  6. function foo($a, $b){
  7. echo $a+$b;
  8. }
  9. }

抱歉,这样写的结果将会是直接的报错。PHP并不支持这样的重载能力。而在PHP的官方手册上,重载的定义是使用__set()、__get()、__call()、__callStatic()等魔术方法来对无法访问的变量或方法进行重载。这与我们所学习的面向对象中的重载完全不同,在手册中的note里也有很多人对此提出了疑问。当然,我们今天并不会再去讲这些魔术方法的使用。关于它们的使用可以参考我们之前写过的文章:PHP中的那些魔术方法(一)PHP的那些魔术方法(二)

那么,在PHP中可以实现重载吗?当然可以,只不过会麻烦一些:

  1. // 重载
  2. class B
  3. {
  4. public function foo(...$args)
  5. {
  6. if (count($args) == 2) {
  7. $this->fooAdd(...$args);
  8. } else if (count($args) == 1) {
  9. echo $args[0], PHP_EOL;
  10. } else {
  11. echo 'other';
  12. }
  13. }
  14. private function fooAdd($a, $b)
  15. {
  16. echo $a + $b, PHP_EOL;
  17. }
  18. }
  19. $b = new B();
  20. $b->foo(1);
  21. $b->foo(1, 2);

使用一个方法来调用其他方法,根据参数数量来进行判断,就可以实现参数数量不同的方法重载。

  1. // 使用__call()进行重载
  2. class C
  3. {
  4. public function __call($name, $args)
  5. {
  6. if ($name == 'foo') {
  7. $funcIndex = count($args);
  8. if (method_exists($this, 'foo' . $funcIndex)) {
  9. return $this->{'foo' . $funcIndex}(...$args);
  10. }
  11. }
  12. }
  13. private function foo1($a)
  14. {
  15. echo $a, PHP_EOL;
  16. }
  17. private function foo2($a, $b)
  18. {
  19. echo $a + $b, PHP_EOL;
  20. }
  21. private function foo3($a, $b, $c)
  22. {
  23. echo $a + $b + $c, PHP_EOL;
  24. }
  25. }
  26. $c = new C();
  27. $c->foo(1);
  28. $c->foo(1, 2);
  29. $c->foo(1, 2, 3);

使用__call()魔术方法或许会更简单,但也会让一些新手在接手项目的时候蒙圈。毕竟魔术方法对IDE是不友好的,这样的开发让__call()成为了一个模板方法,由它来定义操作的算法骨架。我们也可以根据参数类型来模拟重载能力。

  1. // 参数类型不同的重载
  2. class D {
  3. function __call($name, $args){
  4. if($name == 'foo'){
  5. if(is_string($args[0])){
  6. $this->fooString($args[0]);
  7. }else {
  8. $this->fooInt($args[0]);
  9. }
  10. }
  11. }
  12. private function fooInt(int $a){
  13. echo $a . ' is Int', PHP_EOL;
  14. }
  15. private function fooString(string $a){
  16. echo $a . ' is String', PHP_EOL;
  17. }
  18. }
  19. $d = new D();
  20. $d->foo(1);
  21. $d->foo('1');

不管怎么说,用上述方法实现的方法重载都非常麻烦,因为会让某一个方法或者魔术方法非常重,它需要成为一个控制器来根据参数对内部的方法进行调度。更多的情况下,我们应该还是使用不同的方法名然后抽象公共的部分提取成独立的私有内部方法来实现不同方法名的“重载”。毕竟不同的语言还是要掌握它们不同的个性,并且根据这些个性灵活地运用在我们的项目中。

测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/201912/source/PHP%E4%B8%AD%E7%9A%84%E2%80%9C%E9%87%8D%E8%BD%BD%E2%80%9D%E6%98%AF%E4%B8%AA%E5%95%A5%EF%BC%9F.php

参考文档:
https://www.php.net/manual/zh/language.oop5.overloading.php#77843

===============

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

原文链接:http://www.cnblogs.com/zyblog-coder/p/14365960.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号