[url=http://en.wikipedia.org/wiki/Reference_type]引用类型(Reference)[/url]在许多计算机语言中都被使用,而且是作为一个非常强大而实用的特性存在。它有类似[url=http://en.wikipedia.org/wiki/Pointer_%28computer_programming%29]指针(Pointer)[/url]的实现,却又有不同于指针的表现。例如C++的引用,可以让不同变量指向同一个对象,同时又保有直接使用dot来获取对象成员,不用繁琐的使用[url=http://en.wikipedia.org/wiki/Dereference_operator]dereference运算符(*)[/url]和[url=http://publib.boulder.ibm.com/infocenter/comphelp/v7v91/index.jsp?topic=%2Fcom.ibm.vacpp7a.doc%2Flanguage%2Fref%2Fclrc13cplr034.htm]Pointer to Member运算符(->)[/url]。Java和C#中就直接以引用为主要类型,尽量让开发人员避免使用指针。
PHP中也引入了引用类型,在对对象赋值传递上,基本可视为是同于Java/C#的引用传递(具体请见[url=http://php.net/manual/en/language.oop5.references.php]Objects and references[/url])。但同时又支持在基础类型上通过引用运算符(&)来获得内容的引用。不过在实际的使用中,PHP的引用类型因为整个PHP设计结构而存在着许多的问题,使得在程序出现非预计的结果。
[b]引用变量可被赋予新的引用[/b]
在C++中,引用类型的变量只能在其定义时被赋予引用值,所以我们只要追踪到变量的定义处就可以知道变量是在操作哪个内容。
但是PHP不同,PHP里模糊了变量的定义,可以不定义就使用的变量。所以可以让变量被多次赋予引用值。
[url=http://float-middle.blogspot.com/2010/02/php-references-to-array-elements-are.html]《PHP: References To Array Elements Are Risky》[/url]和 Symmetric Designs的[url=http://www.symmetricdesigns.com/blog/php/2-problems-waccessing-a-php-array-by-reference.html]《Problems w/accessing a PHP array by reference》[/url]里有谈到这个,但是也没有讲原因。
之后又在PHP的Bug Report中看到几篇有联系的报告([url=https://bugs.php.net/bug.php?id=6417]Bug6417[/url], [url=https://bugs.php.net/bug.php?id=7412]Bug7412[/url], [url=https://bugs.php.net/bug.php?id=15025]Bug15025[/url], [url=https://bugs.php.net/bug.php?id=20993]Bug20993[/url])。有些说这是个Bug,而且已经在后边的版本被修复。具体我也没有明白,只能避免在数组上使用引用。
更有趣的事情是,如果unset那些引用,只留下一个,那么数组元素又会变成不含有引用的正常类型。
[url=http://php.net/manual/en/language.types.array.php#language.types.array.examples.changeloop]PHP Array Manual[/url]里面提到的要注意的地方,最常发生在foreach的之中,希望通过引用来改变远数组的值(可参见[url=http://schlueters.de/blog/archives/141-References-and-foreach.html]该篇文章[/url])。
其实想通过使用foreach配合引用来改变数组元素的值,主要是因为PHP的数组是[url=http://en.wikipedia.org/wiki/Associative_array]Associative Array[/url],这种数组“不定长度,索引可以不连续,可同时用字符串和整数当索引”,所以我们无法用for循环简单增加整数索引。
当然我们可以像下边的代码那样通过$key直接对数组元素改变值,但是这可能存在一定的效率问题。
[url=http://www.php.net/manual/en/language.references.pass.php]在函数调用中使用引用传递参数[/url]。其主要原因是希望通过这种方法让函数实现返回多个返回值。比如我们希望用一个表示指示函数是否在执行中出现error而导致返回值是无效的。
但是因为PHP的函数是可以返回不同的类型的,所以并不需要传入引用参数来作为表示。即使真的需要多个返回值,也可以通过返回“以字符串为主键的数组”作为解决方案,只不过可能需要在文档中指出每个元素都是对应那个结果。
有一个比较好操作方式,应该是每当引用变量[b]不再需要使用[/b]时,就即时对该变量使用unset让它切换与内容之间的联系。而且即使该变量不是引用类型,我们[b]确认它不再被使用[/b],对它调用unset也不会有什么问题。至少保证在之后对该变量重新赋值时,并不会影响到之前的结果。
[list=1]
[*][url=http://www.symmetricdesigns.com/blog/php/2-problems-waccessing-a-php-array-by-reference.html]Problems w/accessing a PHP array by reference - Symmetric Designs[/url]
[/*][*][url=http://float-middle.blogspot.com/2010/02/php-references-to-array-elements-are.html]PHP: References To Array Elements Are Risky – Float Middle[/url]
[/*][*][url=http://schlueters.de/blog/archives/141-References-and-foreach.html]References and foreach - Johannes Schlüter[/url]
[/*][*][url=http://us3.php.net/manual/en/language.references.php#79220]References Explained - PHP Manual[/url][/*][/list]