PHP重载基础知识回顾

重载和重写

先区分一下重载(overload)和重写(override):重载指多个名字相同,但参数不同的函数在同一作用域并存的现象;重写出现在继承中,指子类重定义父类功能的现象,也被称为覆盖。重载中说的参数不同有三种情况:参数个数不同,参数类型不同,参数顺序不同。重写一般指函数的覆盖,即相同签名的成员函数在子类中重新定义(实现抽象函数或接口不是重写),是实现多态(polymorphism)的一种关键技术。成员变量也可以重载/覆盖,但一般不会这么做。

用简单的C代码来说明重载:

int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
double add(int a, int b, double c) { return a + b + c; }
double add(double a, int b, int c) { return a + b + c; }

第一个函数为参考基准,其他三个对应重载的三种情形。函数重载多见于强类型语言,编译后函数在函数符号表的名称一般是函数名加参数类型。上面的四个函数,g++编译后,nm命令查看符号表中的名字,输出如下:

[tlanyan@server ~]# nm test | grep add
0000000000400730 t _GLOBAL__sub_I__Z3addii
0000000000400851 T _Z3adddd
00000000004008b1 T _Z3adddii
000000000040083d T _Z3addii
000000000040087d T _Z3addiid

最后四行的第三列对应编译后四个函数的符号信息,_Z3为前缀,add是函数名,剩下的字母d代表double,i代表int,与生命一一对应。

再回到PHP的重载。PHP的函数声明中参数无需声明类型,直接排除参数类型不同、参数顺序不同两种重载,只剩下参数个数不同一条路可走。定义一个参数个数不同名字相同的函数,这么一个小小的重载要求,在PHP中也是不合法的!原因是PHP中不允许同名函数存在,想定义重名函数,死心吧!虽然大多数情况下以默认参数方式实现重载基本上够用,但不时还会觉得憋屈,忍不住想问一句:PHP为什么不允许(同名函数)重载啊?!

PHP的苦衷

PHP不支持同名函数的重载是有原因的。上面已经提到,PHP函数声明时不需要指定参数类型,重载中的三种情况立马废掉两种。幸存的参数个数不同这一条路也走不通,为什么呢?因为PHP中调用函数时,少传参数,不行;多传参数,没问题!来个简单的例子:

function foo($arg1, $arg2) {
  echo "$arg1, $arg2\n";
}

// 函数调用
// 参数过少,提示:
//PHP Warning: Missing argument 2 for foo()
// PHP Notice: Undefined variable: arg2 in php shell code on line 2
foo("tlanyan");

// 参数个数正好,运行正常
foo("hello", "tlanyan");

// 多传参数,运行正常
foo("hello", "tlanyan", "nice day");

// 传更多参数,也一切正常
foo("hello", "tlanyan", "morning", "noon", "afternoon", "evening", "night");

只要个数不小于声明的,传多少参数PHP不管。所以参数个数不同,在PHP中不足以区分函数。

个人认为另一个不允许名函数存在的重要原因是function_existsmethod_existsis_callable这些API的存在。作为简单易用的语言,PHP为开发人员提供了查询函数名是否存在/可用的便利API,这在编程语言中很少见(尤其是get_defined_functions这类API)。可以看到,这些API都不需要参数信息。如果能定义参数不同的重载函数,这些API都要跟着改,势必引入额外的复杂性。正所谓鱼与熊掌不可兼得,方便你用时没想到参数不同,不方便你定义就抱怨,好像不好吧?

PHP5引入了反射API,这是非常强大的类型信息查询工具。就函数声明而言,ReflectionMethod/ReflectionFunction类的getParameters/getNumberOfParameters/getNumberOfRequiredParameters等API,功能上甩function_exists等好几条街。有了反射机制,按理说function_exists这些API可以安心的退休。虽然反射这一套东西功能强大,但远没有旧式API简单好用。再加上看看市面上的代码,有多少类库和框架依赖旧式API。从兼容性和实用性考虑,个人认为短时间内能以同名函数方式重载的概率非常小。

PHP中的重载

只看完上面的内容就说PHP不支持重载,我想随便一个资深的PHP开发都会不由自主的取下拖鞋,然后教你什么是PHP中的重载,并保证至少有好几种实现方法;官方人员对这种认知估计也无力吐槽:能不能好好看官方文档?!官网中可是有一节专门讲重载!

因为种种原因,PHP不支持传统的重载,也就是同名函数的重载,但PHP是支持重载的,而且姿势还不少。简单来说,PHP中主要有以下几种重载方式:

  1. 默认参数,定义一个全面的函数版本,不是必须的值在声明时赋予默认值;
  2. 定义一个不声明参数的入口函数,函数内使用func_num_args/func_get_args获取参数个数/数组,然后根据参数个数转发到具体实现的函数;
  3. 自PHP5.6起,可以用变长参数实现重载,func_get_args的另一种形式;
  4. 对于类中的成员函数,可以通过__call和__callStatic实现重载。

如果你还知道其他方式,欢迎评论给出方案。

总结

PHP的特性决定了其不支持同名函数方式的重载,但并不意味着PHP不支持重载。实际上PHP可以多种方式实现重载,并保持其一贯的简单易用性。

感谢阅读!

以上就是PHP重载基础知识回顾的详细内容,更多关于PHP 重载的资料请关注我们其它相关文章!

时间: 2020-09-07

PHP利用func_get_args和func_num_args函数实现函数重载实例

本文实例讲述了PHP利用func_get_args和func_num_args函数实现函数重载的方法.分享给大家供大家参考.具体方法分析如下: 学习php的朋友都知道php本身是没有函数重载这一说的,更没说像java,c那样使用方法,但如果我们深入了解一下会发现可以在php中使用func_get_args()和func_num_args()函数实现函数重载,下面来举两个函数重载例子.这两个函数实现函数的重载. 1.默认参数,如果一个函数里面,这不是必须参数,而添加相应的默认值,就可以完成相应的功

php 使用 __call实现重载功能示例

本文实例讲述了php 使用 __call实现重载功能.分享给大家供大家参考,具体如下: <?php /** * Created by PhpStorm. * User: funco * Date: 17-6-9 * Time: 下午1:39 */ class MulStat { // showClass 可以接受0个参数 private function showClass() { echo "this is class ".__CLASS__; } // showString

PHP中子类重载父类的方法【parent::方法名】

在PHP中不能定义重名的函数,也包括不能再同一个类中定义重名的方法,所以也就没有方法重载.单在子类中可以定义和父类重名的方法,因为父类的方法已经在子类中存在,这样在子类中就可以把从父类中继承过来的方法重写. 子类中重载父类的方法就是在子类中覆盖从父类中继承过来的方法,父类中的方法被子类继承过来不就可以直接使用吗?为什么还要重载呢?因为有一些情况我们必须要覆盖的.例如,有一个"鸟"类,在这个类中定义了鸟的通用方法"飞翔".将"鸵鸟"类作为它的子类,

PHP使用方法重载实现动态创建属性的get和set方法

在PHP中,我们不能够直接通过方法名相同,签名不同的方法来实现方法重载,因为PHP是弱数据类型,不能很好的区分签名.但是,可以在PHP的类中运用__call()方法来实现方法重载.当调用一个类中并不存在的方法时,会自动调用__call()方法,其形式为__call($name,$arguments) 其中$name是方法的名称,$arguments是一个数组类型的参数. 下面的例子是使用PHP的方法重载来动态创建get和set方法.(在面向对象编程中,一个类中的属性会使用get和set来赋值,但

php继承中方法重载(覆盖)的应用场合

本文实例分析了php继承中方法重载(覆盖)的应用场合.分享给大家供大家参考.具体分析如下: 方法重载(override)/覆盖--在什么情况下使用:当父类知道所有的子类都需要用到一个方法,但父类不知道怎么去写这个方法时,就需要用到方法的重载.这时候,可以让子类去重写,来覆盖这个方法. 通俗实例--父类(动物)知道其子类(猫和狗)都会叫,但它们的叫法都不一样,所以父类没法去写这个方法,只能让子类(猫和狗)去定义.代码如下: <?php class Animal{ public $name; pro

PHP面向对象编程之深入理解方法重载与方法覆盖(多态)

什么是多态? 多态(Polymorphism)按字面的意思就是"多种状态".在面向对象语言中,接口的多种不同的实现方式即为多态.引用Charlie Calverts对多态的描述--多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自"Delphi4编程技术内幕").简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针(没错这段话来自百度百科).那么多态的作用是什么,它有

php函数重载的替代方法--伪重载详解

函数重载的替代方法-伪重载,下面看一个具体的实例代码. <? php //函数重载的替代方法-伪重载 // //确实,在PHP中没有函数重载这个概念,让很多时候我们无法进行一些处理,甚至有时候不得不在函数后面定义好N个参数 //在看到了func_get_arg,func_get_args,func_num_args,这三个函数的时候,你们是不是想起了什么? function testOne ( $a ) { echo (' 一个参数就这样 '); } function testTwo ( $a

php面向对象全攻略 (八)重载新的方法

12.重载新的方法 在学习PHP 这种语言中你会发现,PHP 中的方法是不能重载的,所谓的方法重载就是 定义相同的方法名,通过"参数的个数"不同或"参数的类型"不同,来访问我们的相同方法 名的不同方法.但是因为PHP 是弱类型的语言,所以在方法的参数中本身就可以接收不同类 型的数据,又因为PHP 的方法可以接收不定个数的参数,所以通过传递不同个数的参数调用 不相同方法名的不同方法也是不成立的.所以在PHP 里面没有方法重载.不能重载也就是在 你的项目中不能定义相同方

PHP面相对象中的重载与重写

重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现.Overloaded的方法是可以改变返回值的类型.也就是说,重载的返回值类型可以相同也可以不同. 重载(Overloading) a.方法重载是让类以统一的方式处理不同类型数据的一种手段.多个同名函数同时存在,具有不同的参数个数/类型.重载Overloading是一个类中多态性的一种表现. b.Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的

PHP面向对象程序设计模拟一般面向对象语言中的方法重载(overload)示例

本文实例讲述了PHP模拟一般面向对象语言中的方法重载(overload).分享给大家供大家参考,具体如下: 在一般的面向对象设计语言(如C++,Java)中的方法重载就是定义相同的方法名,通过"参数的个数"不同或"参数的类型"不同,来访问我们的相同方法名的不同方法.但是PHP 中,方法是不能重载的,因为PHP 是弱类型的语言,所以在方法的参数中本身就可以接收不同类型的数据,又因为PHP 的方法可以接收不定个数的参数,所以通过传递不同个数的参数调用不相同方法名的不同方

解决PHP Opcache 缓存刷新、代码重载出现无法更新代码的问题

问题背景 通过启用Opcache的缓存优化,将PHP代码预编译为Opcode缓存到共享内存中供进程反复调用,从而减少了重复从磁盘解析PHP代码的时间消耗,显著的提高了PHP性能,提升了业务性能的调用,但是也引发了一些问题,就是我们每次更新了相应的PHP代码后,web server 无法即时加载到更新后的代码. 解决方案 (一).设置Opcache脚本验证时间 可以通过更改 Opcache 以下两个配置选项来调整代码重载时间 opcache.revalidate_freq=0 检查脚本时间戳是否有

php面向对象的方法重载两种版本比较

多个函数用同一个名字,但参数表,即参数的个数或(和)数据类型可以不同,调用的时候,虽然方法名字相同,但根据参数表可以自动调用对应的函数. PHP4 中仅仅实现了面向对象的部分的.简单的功能,而 PHP5 以后对对象的支持就强大的多了. 对于多态的实现,PHP4 只支持覆盖(override),而不支持重载(overload).但我们可以通过一些技巧来"模拟"重载的实现. PHP5 虽然可以支持覆盖和重载,但重载在具体实现上,和其他语言还有较大的差别. 1,在 PHP4 中"模

php面向对象与面向过程两种方法给图片添加文字水印

目前绝大多数PHP程序员使用面向过程的方式,因为解析WEB页面本身就非常"过程化"(从一个标签到另一个标签).在HTML中嵌入过程处理代码是很直接自然的作法,所以PHP程序员通常使用这种方式. 如果你是刚接触PHP,用面向过程的风格来书写代码很可能是你唯一的选择.但是如果你经常上PHP论坛和新闻组的话,你应该会看到有关"对象"的文章.你也可能看到过如何书写面向对象的PHP代码的教程.或者你也可能下载过一些现成的类库,并尝试着去实例化其中的对象和使用类方法--尽管你可

JS类定义原型方法的两种实现的区别评论很多

我们知道,给JavaScript类添加原形(prototype)方法是很简单的.而且常用的有下面这两种方法,可是这两种方法在使用时有区别吗?     JScript Class:  复制代码 代码如下: function JSClass()   {        } Extends prototype method:  复制代码 代码如下: JSClass.prototype.MethodA = function()   { }; Or   复制代码 代码如下: function = JSCla

python学习之第三方包安装方法(两种方法)

这篇文章主要介绍了python学习之第三方包安装方法,最近在学习QQ空间.微博(爬虫)模拟登录,都涉及到了RSA算法.这样需要下一个RSA包(第三方包),在网上搜了好多资料,具体有以下两种方法: 第一种方法(不使用pip或者easy_install): Step1:在网上找到的需要的包,下载下来.eg. rsa-3.1.4.tar.gz Step2:解压缩该文件. Step3:命令行工具cd切换到所要安装的包的目录,找到setup.py文件,然后输入python setup.py install

js数组的五种迭代方法及两种归并方法(推荐)

js数组的五种迭代方法及两种归并方法(推荐) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta ht

mybatis 加载配置文件的方法(两种方式)

一. 使用sqlSessionFactory 的 mapperLocations 进行加载, <!-- SessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" scope="singleton"> <property name="dataSource" ref=

spring boot @ResponseBody转换JSON 时 Date 类型处理方法【两种方法】

spring boot @ResponseBody转换JSON 时 Date 类型处理方法[两种方法],Jackson和FastJson两种方式. spring boot @ResponseBody转换JSON 时 Date 类型处理方法 ,这里一共有两种不同解析方式(Jackson和FastJson两种方式) 第一种方式:默认的json处理是 jackson 也就是对configureMessageConverters 没做配置时 mybatis数据查询返回的时间,是一串数字,如何转化成时间.

ajax的两种提交方式(get/post)和两种版本

最近比较闲,就把以前用过的技术串一下做个手札,方便以后自己偷懒,小鸟你们幸福了. 首先主要是将javascript版本ajax做下注释:ajax异步刷新主要是将所需条件拼成字符串传入后台,处理之后,直接调用回调函数将所得数据返还给页面,并加以显示,因为还在本页面,所以不用刷新页面,懂了了吧,本篇也用encodeURI对字符串做了加密,并在类里做了解码,其中需要一些注意的地方在源码里做了注释.get/post两种提交方式,但get提交容易乱码,一定多加注意 jsp页面: 复制代码 代码如下: <%

JS类中定义原型方法的两种实现的区别

我们知道,给JavaScript类添加原形(prototype)方法是很简单的.而且常用的有下面这两种方法,可是这两种方法在使用时有区别吗? JScript Class: function JSClass() { } Extends prototype method: JSClass.prototype.MethodA = function() { }; Or function = JSClass.prototype.MethodA() { }; 其实这两个原形定义方式可以简化一下来讨论,先把它

java中常用的字符串的比较方法(两种)

比较字符串比较常用的两个方法是运算符"="和String的equals方法. 使用"="比较两个字符串,是比较两个对象的的"地址"是否一致,本质就是判断两个变量是否指向同一个对象,如果是则返回true,否则返回的是false.而String类的equals方法则是比较两个字符串的内容是否一致,返回值也是一个布尔类型. 看下面的代码: public class TestString{ public static void main(String[]