第5章函数、数组与字符串操作
学习目标:
本章将介绍PHP 语言中函数、数组和字符串的相关知识,包括其概念和语法规则。通
过本章的学习可掌握函数及数组的语法规则和字符串的相关操作,在编写程序时能够熟练
运用函数解决实际问题。本章学习要求如表5-1所示。
表5-
1
本章学习要求
知识要点能力要求相关知识
函数理解函数的概念,掌握函数的语法规则关键字、实参、形参、调用
数组理解数组的概念,掌握数组的语法规则一维数组、二维数组
字符串掌握字符串的相关操作,了解正则表达式
PHP 是一个热门的脚本语言,是从Perl和C语言发展而来的,与Perl和C语言有很多
相似之处,用PHP 语言可进行关于函数、数组与字符串的定义和相关操作,其基本内容可
以包括函数的基本知识、一维数组、多维数组、数组排序、基本的字符串函数和正则表达
式等。
5.函数
1
函数就是一段能够完成指定任务的已命名的PHP 代码,这段代码可以有很少几个语
句,也可以有几百行语句,可以遵照给它的一组值和参数来完成指定的任务,并且可能返回
一个函数值。使用函数能够节省程序的编译时间,无论调用函数多少次,只需要页面进行一
次编译,则可提高程序执行效率。使用函数的好处在于能够分离相关PHP 代码,按照功能
的不同设置不同的程序模块,欲实现某个功能时,只需要调用相应的函数,则可实现代码的
重用,提高程序的可读性和可维护性。
利用函数进行模块化程序设计时,首先需要了解一些基本知识,包括函数的一般形式、
参数和返回值,函数的调用方式和变量的作用域以及生命周期等。
1.函数的一般形式
5.1
PHP 中的函数包括内置函数和自定义函数两种类型。内置函数是PHP 中已经定义的
完成特定功能的函数,不需要对函数体进行修改就可以直接调用。自定义函数是程序设计
者为了实现特殊的目的而编写的代码段,在PHP 中自定义函数要用到关键字function,这
表示使用者要进行自定义函数的编写。
PHP 中的函数和其他高级语言一样,包括有返回值和无返回值两种类型。函数的命名
规则与C语言相似,只能由字母,数字和下画线构成,且不能以数字开头,函数名称不区分
·109·
大小写。
要定义一个函数,可以使用下面的语法结构:
function function_name($arg1,$arg2,…)
{
statement list //执行的操作
.r
eturn $result; //函数的返回值,也可以没有
}
其中,function是关键字,代表要定义一个自定义函数;function_name是自定义函数的名
称;arg1、arg2是函数的参数(即传递变量);statementlist是函数体,完成指定的任务,函数
体除了包含PHP代码外,还可以包括HTML代码;return语句后面紧跟着函数的返回值,
当函数在执行期间遇到return语句时,将跳出函数体返回到调用语句,并将变量result的
值作为函数值返回,一个函数体内可以包含多个return语句。
【例5-1】 定义一个函数,实现两个字符串的连接。
\n";
}
?>
这个函数的输出结果是str1和str2两个字符串连接的结果。
在自定义函数时,函数的参数既可以在函数调用时进行赋值,也可以预先赋值,在函数
定义的时候将初始值赋给参数。
【例5-2】 定义一个函数,实现3个字符串连接。
\n";
}
?>
这个函数的特点在于当函数定义时,参数列中使用了预先赋值的参数。
定义过一个函数后,可以在程序的任何地方对函数进行调用,完成特定的功能。在自定
义函数时,一个非常好的习惯是根据函数要完成的功能来给函数命名,良好的命名习惯不仅
能增加程序的可读性,还有利于程序的调试和排错。
5.1.2 函数参数与返回值
1.函数的参数
在函数定义的语法格式中,函数名后“()”中的变量就是函数的参数(即传递变量)。参
·110·
数可以有,也可以没有;可以是一个,也可以是多个。通过参数可以将信息传递到函数体中,
参数可以是变量,也可以是常量,当一个函数包括多个参数时,各个参数中间用“,”进行
分隔。函
数参数的传递有两种方式:按值(value)传递和按引用(reference)传递。
(1)按值传递参数。PHP中大多数情况下是按值传递参数,传递的是变量值,而不是
变量在内存中的实际地址。在调用函数时,传递给函数的参数只是变量的一份副本,在函数
体内对这份副本的任何操作都不会影响到原来变量的值。函数利用传递过来的值进行计
算,再将结果返回,函数外的变量在内存中的地址不变,其变量值也不变。
【例5-3】 一个函数参数按值传递的简单例子。
在这个例子中,使用按值传递的方式给square()函数传递了变量a的值作为参数进行
计算,函数的输出结果为2。由于传值只是在函数体内改变参数的复制值,并不会改变原变
量的值,所以最后输出变量a的值仍为2而不是4。
(2)按引用传递参数。程序设计中,有时希望函数能够对参数传递过来的变量值进行
改动,并且这些改动能够在函数之外体现出来,这时就需要按引用方式来传递参数,这种方
式可以对变量作直接的修改。
按引用传递参数时,参数必须是一个变量,并且要在参数列表中的变量名前加“&”表明
该变量将按引用传递。按引用传递参数时,传递的是变量在内存中的地址,函数利用这个地
址访问其所指的值,并改变这个值,从而使得变量的值发生改变。
【例5-4】 按引用传递参数的例子。
本例采用的是按引用传递参数,将$a的地址所指向的值2传递出去,并且这个值发生
了变化,$a也相应发生变化,$a所处的内存地址所指向的值已经发生了变化,最后的输出
结果是4,变量a的最终值也是4。
·111·
按引用传递参数与按值传递参数一样,在调用参数时没有什么区别,都是在函数体内直
接使用。
(3)默认参数值。自定义函数时,还可以给函数的参数赋一个初始值作为默认参数值,
在调用函数时,即使没有给函数传递参数,函数也能够按照默认参数值来执行。
要指定一个默认参数,可以在函数声明时赋予该参数一个初始值,并且这个初始值只能
是一个常量。
【例5-5】 默认参数值举例。
";
}s
tringcon("life ","is ");
echo "
";
stringcon("life ","is ","very beautiful!");
?>
在这个例子中,首先定义了一个字符串连接函数,它一共有3个参数,其中前两个是普
通参数,第三个参数具有默认参数值。函数的功能是将参数传递过来的字符串连起来,并在
屏幕上显示出来。程序对定义的函数按照传值方式进行了两次调用,第一次调用时,给函数
传递了两个参数值,第三个参数使用默认值;第二次调用时,给函数传递了3个参数值,所以
函数直接将传递过来的3个字符串连接起来,输出结果。输出结果如下:
life is beautiful.
life is very beatiful!
使用默认参数还需要注意的默认参数的书写位置,有默认值的函数参数必须放在没有
默认值的参数后面,即默认参数必须应放在参数列表的最后,否则PHP在执行函数时会出
现无法预料的结果。
【例5-6】 默认参数的书写位置不同造成程序执行结果与预期不符。
";
}s
tringcon("Everybody ");
?>
这个例子的输出结果是“Everybody”,并不是预期的“everybodycansucceed!”。为了
能够达到程序预期的执行效果,需要对自定义函数的参数位置进行调换,将默认参数放到参
数表的最后。
【例5-7】 将默认参数放到参数表最后。
·112·
";
}s
tringcon("Everybody ");
?>
经过修改后本例的输出结果是“Everybodycansucceed!”,达到了程序的预期执行
效果。一
个自定义函数中可以有任意数目的带有默认参数值的参数,但这些参数必须列在所
有没有默认值的参数后面。
2.函数返回值
在程序设计中,当一个函数被调用后,有时需要其返回一个或多个结果,这就是函数的
返回值。在PHP中,可以使用关键字return来获得函数的返回值,且函数的返回值可以是
任何类型的数值,包括数组和对象。
当需要函数返回单个结果时,可以直接使用return语句来实现。而当需要函数返回多
个结果时,可以通过数组或者广义表等来实现。
【例5-8】 一个函数返回单个值。
这个例子实现的功能是将3个数相乘并返回一个相乘的结果,最后的输出结果是24。
【例5-9】 一个函数的返回多个值。
这个例子实现了一个函数返回多个值的功能,这个函数实现3个数相加的功能,共返回
了4个值,包括传递过来的3个参数和最终计算结果。
·113·
5.1.3 函数调用
函数调用分为3种形式:一般调用、嵌套调用和递归调用。
1.一般调用
函数的一般调用就是普通的函数调用,即直接用函数名称来调用函数,这也是函数调用
最常用的方式。其调用形式如下:
$some_value =function_name([parameter,…]);
其中,some_value是函数的返回值;function_name是函数的名称;parameter是函数的参
数,可以省略,也可以是多个。
如果调用的是不带参数的函数,则parameter可以省略,但“()”不能省略。如果实参列
表包含多个参数,则各参数之间用“,”分隔。实参与形参的个数应该相等(默认参数可以省
略),且实参与形参的顺序必须对应。
【例5-10】 比较两个数大小。
y)
return x;
else
return y;
}e
cho max(10,3);
?>
本例为函数的一般调用,通过使用max(10,3)的形式来调用自定义max()函数,最终
的输出结果为“10”。
2.嵌套调用
函数的嵌套调用是指在一个自定义函数中调用其他自定义函数,其调用的语法格式与
普通调用语法格式相同。
【例5-11】 函数的嵌套调用。
";
}f
unction A ($a)
{
$c=$a+$a;
B($a);
echo $c."
";
·114·
} A(4);
?>
本例在定义函数A()时对函数B()进行调用,属于一个典型的函数嵌套调用。程序的
执行过程如下。
(1)执行程序A 的前半部分“$c=8”。
(2)调用程序B。
(3)执行程序B:“$b=16”并且输出$b的值。
(4)返回到程序A,继续执行程序A 的后半部分:输出$c的值,直到结束。
本例的运行结果是通过屏幕显示16和8。
3.递归调用
函数的递归调用是指在一个函数内部直接或间接地调用函数本身,其调用的语法格式
与普通调用语法格式相同。需要注意的是,递归调用函数内部要有终止条件,否则会无限调
用下去。
递归调用的特点是,将大而复杂的问题分解成与原问题相同但规模较小的问题,通过解
决这些小规模问题,从而最终解决大而复杂的问题。
【例5-12】 求一个数的阶乘。
问题分析:要想求出n 的阶乘,首先需要求出n-1的阶乘,即n!=n×(n-1)!,重复
这个求解过程,直到n=1为止。要解决这个问题就需要通过函数的递归调用来实现。
";
else
if ($a==0||$a==1)
$result=1;
else
$result=mul($a-1)*$a; //此处进行函数的递归调用
return ($result);
} $c=mul(5); //输出5 的阶乘
echo $c;
?>
在这个例子中,定义函数mul()时,在函数体内对其自身进行了调用,属于一个典型的
函数嵌套调用。程序的运行结果为120。
汉诺塔问题是一个古典的数学问题,也是一个用递归方法求解的典型例子。
【例5-13】 汉诺塔问题。从前,一个寺院有3根柱子(1号为原始柱,2号为交换柱,3
号位目标柱),1号柱上小下大地放着64个金盘(依次由小到大),有一队和尚想将这64个
·115·
金盘从1号柱移到3号柱上。规则是一次只允许移动一个,且在移动过程中,在3根柱子上
都始终保持大盘在下,小盘在上。在移动过程中可以利用2号柱。全部移动完需要多长时
间。要求编程序输出移动步骤。
程序代码如下:
".$e."
";
}
function hanoi($n,$a,$b,$c)
{
if ($n==1)
{
move($a,$c);
}
else
{
hanoi($n-1,$a,$c,$b);
move($a,$c);
hanoi($n-1,$b,$a,$c);
}
}
$num=4;
$step=0;
hanoi($num,"one","two","three");
?>
在本程序的代码中,函数hanoi($n,$a,$b,$c)表示将$n个盘子从$a借助$b移
到$c的过程。函数调用move($d,$e)表示将一个盘子从$d移到$e的过程。$d和
$e都表示one、two、three3根柱子中的一根,根据每次情况不同取值,最终完成求解任务。
5.1.4 变量的作用范围和生命周期
变量的作用范围和生命周期是变量的两个很重要的性质,决定了程序的哪些部分可以
访问变量,以及变量的生存时间。
1.变量的作用范围
变量的作用范围,即通常所说的变量作用域,指的是变量在哪些范围内能被使用,在哪
些范围内不能被使用。在使用PHP语言进行程序开发时,可以在任何位置声明变量,但是
变量声明位置及声明方式的不同决定了变量作用域的不同。
·116·
在PHP中,按照变量作用域的不同可以将变量分为局部变量和全局变量两种。
(1)局部变量。同其他程序语言类似,PHP中的局部变量是声明在某一个函数体内的
变量,该变量的作用范围仅限于其所在的函数体的内部,函数外的代码不能访问这个变量。
如果在该函数体的外部引用这个变量,PHP将会认为程序引用的是另外一个同名变量。
【例5-14】 局部变量应用举例。
";
}l
ocal();
$a="outside var."; //在函数外部再次声明变量a 并赋另一个值
echo "函数外部变量a 的值为".$a;
?>
本例中,由于两个变量a声明的位置不同,所以为两个不同的变量。其执行后的输出结
果如下:
函数内部变量a 的值为inside var.
函数外部变量a 的值为outside var.
(2)全局变量。在函数以外声明的变量为全局变量,它的作用范围最广泛,可以在程序的
任何地方被访问。但是在默认情况下,不能在一个函数体内访问全局变量,要想在函数中访问
一个全局变量,需要在函数中使用关键字global(不区分大小写,也可以是GLOBAL)。
通过使用全局变量,在程序设计时能够实现在函数内部引用函数外部的变量,或者在函
数外部引用函数内部的变量。
【例5-15】 全局变量应用举例。
";
global $b; //将变量b 声明为全局变量
$b="global var."; //在local 函数内部对变量b 进行赋值
}l
ocal();
echo "在local 函数外部获得变量b 的值为".$b.
?>
运行结果如下:
在local 函数内部获得变量a 的值为inside var.
在local 函数外部获得变量b 的值为global var.
·117·
将一个变量声明为全局变量,还有另外一种方法,就是利用$GLOBALS[]数组,此处
不再详述。
注意:通过使用全局变量,虽然能够更加方便地操作变量,但是有时变量作用域的扩大
会给程序开发带来麻烦,可能会引发一些预料不到的问题。所以应该谨慎使用全局变量。
2.变量的生命周期
变量的生命周期指的是变量能够被使用的一个时间段,在这个时间段内变量是有效的,
一旦超出这个时间段,变量就会失效,不能再访问到该变量的值。
PHP对变量的生命周期有如下规定。
(1)局部变量的生命周期为其所在函数被调用的整个过程。当局部变量所在的函数结
束时,局部变量的生命周期也随之结束。
(2)全局变量的生命周期为其所在的PHP脚本文件被调用的整个过程。当全局变量
所在的脚本文件结束调用时,全局变量的生命周期结束。
程序设计中,有时希望一个变量的值能在其生命周期之外被调用,这时就需要将变量声
明为静态变量,将一个变量声明为静态变量的方法是在变量前面加关键字static。
【例5-16】 静态变量举例。
"; //输出变量a 的值
$a=$a+2; //将变量a 的值加2 再次赋给变量a
}s
tavar(); //调用函数stavar()
stavar();
echo $a; //变量a 是局部变量,不能在函数外使用,故不会输出任何值
?>
运行结果如下:
02
本例中每次调用函数stavar()时,变量a的值都会增加2。也就是说,每次调用函数结
束以后,变量a都仍然存在,再次调用函数stavar()时,变量a将会使用上一次调用该函数
结束时得到的值。
从上面的例子也可以看出,虽然静态局部变量在函数调用结束后仍然存在,但是其他函
数是不能引用它的。静态局部变量的作用范围与局部变量相同,但是生命周期与全局变量
相同。静
态变量具有以下特点。
(1)只有函数首次被调用时,才会给函数体内静态变量赋初始值。再次调用该函数时,
静态变量保存的是上次调用这个函数后得到的值。
(2)在为静态变量赋初值时,不可以将一个表达式赋给该静态变量。
·118·