Php 3.x与4.x中关于对象编程的不兼容问题
“面向对象”听起来是个很流行的词汇,似乎到了如果你还没有OOP,那不如回家种白菜的地步。
Php从版本3.x开始支持对象编程,虽然它的Class从一开始就饱受程序员们的指责,但它的确给我们带来了意外的惊喜。一路跌跌撞撞走来,到了4.x,Php已经相当OOP了。当然,它对于类变量的处理依然不能让人满意,没有私有、公有、保护、静态的声明方法。Php面向对象的可用性不在本文讨论范围内。
伴随着4.x中关于对象编程的完善,Php team给我们带来了“麻烦”:3.x和4.x中关于对象编程的一些游戏规则改变了,不兼容。笔者就实际开发过程遇到的问题稍作讨论,相信有些问题可能笔者尚未遇到,欢迎诸位补充、共赏。
二、按引用传递参数说
这一节讨论不止适用于Php对象编程,适用于Php编程的所有方面。
Php中的参数默认是按值传递的,不论是基本数据类型还是对象。和其他面向对象编程语言有所区别的是,通常对象在其他语言中的默认传递方式是按引用传递。为了达到按引用传递参数的目的,Php小组引入了一个“&”操作符来声明当前这个变量应该按引用传递。看起来感觉有点怪怪的。
这里不讨论基本数据类型。
1、
- class ABabyStudio *
- { *
- function ABabyStudio(){ *
- echo('call constructor'.chr(13)); *
- } *
- //... *
- } *
- $ABabyStudio1 = new ABabyStudio(); *
- $ABabyStudio2 = $ABabyStudio1; *
- $ABabyStudio3 = & $ABabyStudio1; *
注释:
$ABabyStudio2获得了一个$ABabyStudio1的复制品,而不是$ABabyStudio1本身,就是说以后1变化并不会影响到2,反之亦成立。
$ABabyStudio3将得到$ABabyStudio1的引用,1和3的变化是同步的。
2、
- class ABaby *
- { *
- var $hello; *
- function ABaby(){ *
- $this->hello=' world'; *
- } *
- //... *
- } *
- class ABabyStudio *
- { *
- function ABabyStudio(){ *
- ; *
- } *
- function helloEveryOne($ABaby){ *
- $ABaby->hello=' every one'; *
- } *
- //... *
- } *
- $ABaby=new ABaby; *
- echo($ABaby->hello); *
- $ABabyStudio=new ABabyStudio(); *
- $ABabyStudio->helloEveryOne(& $ABaby); *
- echo($ABabyStudio->hello); *
注释:
你在3.x中运行这段代码,一切OK。换到4.x环境中,问题出现了:
- PHP Warning: Call-time pass-by-reference has been deprecated - argument passed by value; *
- If you would like to pass it by reference, modify the declaration of runtime function name. *
- If you would like to enable call-time pass-by-reference, you can set *
- allow_call_time_pass_reference to true in your INI file. *
- However, future versions may not support this any longer. *
在4.x中,Php向通用模式靠拢。如果想要向一个函数按引用传递参数,应该在函数声明中定义,具体形式就是在形参前加上引用操作符“&”:
- function yourFunction(& $arg){ *
- $arg++; *
- } *
- $arg=7; *
- yourFunction($arg); *
- echo($arg); *
运行这段代码,你将发现$arg的值递增到“8”。所以,代码段2应修改为:
- class ABaby *
- { *
- var $hello; *
- function ABaby(){ *
- $this->hello=' world'; *
- } *
- //... *
- } *
- class ABabyStudio *
- { *
- function ABabyStudio(){ *
- ; *
- } *
- function helloEveryOne(& $ABaby){ *
- $ABaby->hello=' every one'; *
- } *
- //... *
- } *
- $ABaby=new ABaby; *
- echo($ABaby->hello); *
- $ABabyStudio=new ABabyStudio(); *
- $ABabyStudio->helloEveryOne($ABaby); *
- echo($ABabyStudio->hello); *
类似的,如果想要函数返回一个“引用”而不是“拷贝”,同样可以在函数声明中实现,这在3.x中是不可能的:
- function & yourFunction(&$arg){ *
- $arg++; *
- return($arg); *
- } *
- $myArg=7; *
- $argRef=& yourFunction($myArg); *
- $argRef+=10; *
- echo($myArg); *
运行这段代码将发现$arg的值经过两次加法运算变为18。可能有人质疑这一句“$argRef=& yourFunction($arg);”既然函数已经按引用传递回了$arg,为什么还要在这一句中使用“&”?问的好!这是因为,声明函数按引用返回参数$arg后,只是告诉函数(或者Php解析器)在return时不要把$arg拷贝一份送出来,而由于函数体返回值(实际是一个引用)要经历一次赋只“=”操作,所以要函数前面再次出现“&”。这样才保证了内存中自始至终只存在一个$myArg,$myArg的值才会被两次改变。
如果上面的$myArg是一个对象,上面的陈述同样适用。读者可以自己尝试一下。
补充说明一点,依然可以强迫目前的4.x版本支持3.x中的传递引用的方式,可以通过修改php.ini将下面一行:
allow_call_time_pass_reference = Off
改为:
allow_call_time_pass_reference = On
不过,并不保证在后续的版本中继续支持这种方式。