首页 » PHP和MySQL Web开发(原书第4版) » PHP和MySQL Web开发(原书第4版)全文在线阅读

《PHP和MySQL Web开发(原书第4版)》5.10 实现递归

关灯直达底部

PHP支持递归函数。递归函数就是函数调用自己本身。这些函数特别适用于浏览动态数据结构,例如连接列表和树。

但是,几乎没有基于Web的应用程序要求使用如此复杂的数据结构,所以我们很少使用递归函数。在很多情况下,递归可以用来取代循环,因为二者都是重复做一些事情。递归函数比循环慢而且要占用更多内存,所以应该尽可能多用些循环。

为了周全考虑,我们来看一个简单的例子,如程序清单5-5所示。

程序清单5-5 recursion.php——使用递归将一个字符串颠倒是非常简单的

<?php

function reverse_r($str){

if(strlen($str)>0){

reverse_r(substr($str,1));

}

echo substr($str,0,1);

return;

}

function reverse_i($str){

for($i=1;$i<=strlen($str);$i++){

echo substr($str,-$i,1);

}

return;

}

reverse_r('Hello');

reverse_i('Hello');

在这个程序清单中实现了两个函数。这两个函数都可以以相反的顺序打印字符串的内容。函数reverse_r是通过递归实现的,而函数reverse_i是通过循环实现的。

函数reverse_r以一个字符串作为输入参数。当调用它的时候,它会继续调用它自己,每次传递从字符串的第二个到最后一个字符。例如,如果调用:

reverse_r('Hello');

它会用下面的参数多次调用自己:

reverse_r('ello');

reverse_r('llo');

reverse_r('lo');

reverse_r('o');

reverse_r('');

每次调用这个函数都在服务器的内存中生成一段该函数代码的新副本,但每次使用的参数是不同的。这有点像我们每次调用不同的函数。这样会使我们避免将这些函数的调用实例混淆。

在每次调用中,传入字符串的长度都会被测试。当到达字符串末尾的时候(strlen==0),条件失败。最近的一次函数调用(reverse_r(''))会继续执行下一行代码,就是将传入字符串的第一个字符显示出来——在这个情况下没有字符,因为字符串是空的。

下一步,这个函数实例又将控制返回到调用它的实例中,也就是reverse_r('o')。这样就打印出了字符串的第一个字符("o")然后将控制返回到调用它的实例中。

如此继续打印一个字符后返回到调用它的上一层函数实例当中,直到程序控制返回主程序。

在递归方法中有一些非常优美而精确的东西。但是,在大多数情况下,最好还是使用循环方法。循环的代码也在程序清单5-5中给出。请注意,它没有递归方法长(虽然循环函数并不总是这样),但却也能实现相同的功能。最主要的不同在于,递归函数将在内存中创建几个自身的副本,而且将产生多次函数调用的开销。

当递归方法的代码比循环方法的代码更简短、更美观的时候,我们可能会选择使用递归,但是在应用领域通常不会这样。

虽然递归看上去更美观,但程序员常会忘记给出递归的终止条件。这意味着函数会一直重复下去直到服务器内存耗尽,或者达到了最大调用次数。

名称空间

通常,名称空间是一个抽象的容器,它可以包含一组标识符;在PHP中,名称空间可以包含你所定义的函数,常量以及类。从结构的角度看,为自定义函数和类定义名称空间的优点包括如下:

■一个名称空间中的所有函数、类和常量都将自动冠以名称空间前缀。

■非全路径的类、函数和常量名称将在运行时解析,在查看全局空间之前,将首先查看名称空间。

关于PHP中名称空间的更多信息和实用例子,请参阅PHP手册:

http://jp2.php.net/language.namespaces