目录###
一、函数的定义
二、自定义函数
三、函数的工作原理和结构化编程
四、PHP变量的范围
五、声明及应用各种形式的PHP函数
六、递归函数
七、使用自定义函数库
一、函数的定义
一个被命名的、独立的代码段,它执行特定的任务,并可能给调用它的程序返回一个值。定义中的各部分如下:
函数是被命名的:每个函数都有唯一的名称,在程序的其他部分使用该名称,可以执行函数中的语句,成为调用函数。
函数是独立的:无须程序其他部分的干预,函数便能够单独执行其任务。
函数执行特定的任务:任务是程序运行时所执行的具体工作,如将一行文本输出到浏览器、对数组进行排序、计算立方根等。
函数可以将一个返回值返回给调用它的程序:程序调用函数时,将执行该函数中的语句,而这些语句可以将信息返回给调用它们的程序。
PHP的模块化程序结构都是通过函数或对象来实现的,函数则是将复杂的PHP程序分为若干个功能模块,每个模块都编写成一个PHP函数,然后通过在脚本中调用函数,以及在函数中调用函数来实现一些大型问题的PHP脚本编写。使用函数的优越性如下所示:
- 提高程序的重用性
- 提高软件的可维护性
- 提高软件的开发效率
- 提高软件的可靠性
- 控制程序设计的复杂性
二、自定义函数
PHP中的函数分为系统函数和自定义函数,所谓的系统函数是在PHP中提供的可以直接使用的函数,每一个系统函数都是一个完整的可以完成指定任务的代码段。如果某些功能模块在PHP中没有提供系统函数,就需要自己定义函数。
1. 函数的声明
function 函数名([参数1,参数2,...参数n]){
函数体;
return 返回值
}
函数的语法格式说明如下:
- 每个函数的第一行都是函数头,由声明函数的关键字function、函数名和参数列表三部分组成,其中每一部分完成特定的功能。
- 每个自定义函数都必须使用"function"关键字声明。
- 函数名可以代表整个函数,可以将函数命名为任何名称,只要遵循变量名的命名规则即可。每个函数都有唯一的名称,但需要注意的是,在PHP中不能使用函数重载,所以不能定义重名的函数,也包括不能和系统函数同名。给函数指定一个描述功能的名称是一个不错的主意。
- 声明函数时函数名后面的括号也是必须有的,在括号中表明了一组可以接受的参数列表,参数就是声明的变量,然后在调用函数时传递给它值。参数列表可以没有,也可以有一个或多个参数,多个参数使用逗号隔开。
- 函数体位于函数头后面,用花括号括起来。实际的工作是在函数体中完成的。函数被调用后,首先执行函数中第一条语句,执行到return语句或最外面的花括号后结束,返回到调用的程序。函数体中可以使用任何有效的PHP代码,甚至是其他的函数或类的定义也可以在函数体中声明。
- 使用关键字return可以从函数中返回一个值,在return后面加上一个表达式,程序执行到return语句时,该表达式将被计算,然后返回到调用程序处继续执行。函数的返回值为该表达式的值。
代码示例:
/*将使用双层for循环输出表格的代码声明为函数,函数名为table*/
function table() { //函数名为table
echo "<table align='center' border='1' width='600'>";
echo "<caption><h1>通过函数输出表格</h1></caption>";
for($out=0;$out<10;$out++){ //使用外层循环输出表格行
$bgcolor = $out%2 == 0 ? "#FFFFFF" : "#DDDDDD"; //设置隔行变色
echo "<tr bgcolor=".$bgcolor.">";
for($in=1;$in<10;$in++){ //使用内层循环输出表格列
echo "<td>".($out*10+$in)."<td>";
}
echo "</tr>";
}
echo "</table>";
}
table();
输出结果:
2、函数的调用####
不管是自定义函数还是系统函数,如果函数不被调用,就不会执行。只要在需要使用函数的位置,使用函数名称和参数列表进行调用。函数被调用后开始执行函数体中的代码,执行完毕返回到调用的位置继续向下执行。所以在函数调用时函数名称可以总结以下三个作用:
- 通过函数名称去调用函数,并让函数体的代码运行,调用几次函数体就会执行几次。
- 如果函数有参数列表,还可以通过函数名后面的小括号传入对应的值给参数,在函数体中使用参数来改变函数内部代码的执行行为。
- 如果函数有返回值,当函数执行完毕时就会将return后面的值返回到调用函数的位置处,这样就可以把函数名称当做函数返回的值使用。
注:只要声明的函数在脚本中可见,就可以通过函数名在脚本的任何位置调用
table();
function table(){
}
table();
3、函数的参数
定义函数时函数名后面括号内的表达式成为形式参数(简称“形参”),被调用函数名后面括号中的表达式称为实际参数(简称“实参”),实参和形参需要按顺序对应传递数据。
代码示例:
/**
* 自定义函数table()时,声明三个参数,参数之间使用逗号隔开
* @param $tableName 需要一个字符串类型的表明
* @param $rows 需要一个整型数值设置表格的行数
* @param $cols 需要一个整型数值设置表格的列数
*/
function table($tableName,$rows,$cols){
echo "<table align='center' border='1' width='600'>";
echo "<caption><h1>".$tableName."</h1></caption>";
for($out=0;$out<$rows;$out++){
$bgcolor = $out % 2 == 0 ? "#FFFFFF" : "#DDDDDD";
echo "<tr bgcolor=".$bgcolor.">";
for($in=1;$in<$cols;$in++){
echo "<td>".($out*10+$in)."</td>";
}
echo "</tr>";
}
echo "</table>";
}
table("3行4列的表格",3,4);
table("2行10列的表格",2,10);
输出结果:
4、函数的返回值
由于变量的作用域的差异,调用函数的脚本程序不能直接使用函数体里面的信息,但可以通过关键字return向调用者传递数据。return语句在函数体中使用时,有以下两个作用:
- return语句可以向函数调用者返回函数体中任意确定的值。
- 将程序控制权返回到调用者的作用域,即退出函数。在函数体中如果执行了return语句,它后面的语句就不会再执行。
代码示例:
function table($tableName,$rows,$cols){
$str = ""; //声明一个空字符串用来存放表格
$str .= "<table align='center' border='1' width='600'>";
$str .= "<caption><h1>".$tableName."</h1></caption>"
for($out=0;$out<$rows;$out++){
$bgcolor = $out % 2 == 0 ? "#FFFFFF" : "#DDDDDD";
$str .= "<tr bgcolor=".$bgcolor.">";
for($in=1;$in<$cols;$in++){
$str .= "<td>".($out*10+$in)."</td>";
}
$str .= "</tr>";
}
$str .= "</table>";
}
$str = table("3行4列的表格",3,4);
echo $str;
输出结果:
注:函数中不能使用多个return,如果要返回多个值,可以将其放入数组中,使用return返回数组
5、函数的工作原理和结构化编程
通过在程序中使用函数,可以进行结构化编程。在结构化编程中,各个任务是由独立的程序代码段完成的。而函数正式实现“独立的程序代码段”最理想的方式,所以函数和结构化编程的关系非常紧密。结构化编程之所以卓越,有如下两个重要原因:
- 结构化程序更容易编写,因为复杂的编程问题被划分为多个更小的、更简单的任务。每个任务由一个函数完成,而函数中的代码和变量独立于程序的其他部分。通过每次处理一个简单的任务,编程速度将更快。
- 结构化程序更容易测试。如果程序中有一些无法运行的代码,结构化设计则使得将问题缩小到特定的代码段(如特定的函数)。
6、PHP变量的范围####
变量的范围也就是它的生效范围。大部分的PHP变量只有一个单独的使用范围,也包含了include和require引入的文件。当一个变量执行赋值动作后,会随着声明区域位置的差异,而有不同的使用范围。大致上来说变量会依据声明的位置分为局部变量和全局变量两种。
(1)局部变量
局部变量也成为内部变量,是在函数内部声明的变量,其作用域仅限于函数内部,离开该函数后再使用这种变量是非法的。不仅在函数中声明的变量是局部变量,为声明函数设置的参数因为只能在本函数的内部使用所以也是局部变量。区别在于函数的参数具体数值从函数外部获得(函数被调用时传入的值),而直接在函数中声明的变量只能在函数内部被赋值。但它们的作用域都仅限于函数内部,因为当每次函数被调用时,函数内部的变量才被声明,执行完毕后函数内部的变量都被释放。
代码示例:
function demo($one){
$two = 100;
echo "在函数内部执行:$one + $two = ".($one+$two) . "<br/>";
}
demo(100);
echo "在函数外部执行:$one + $two = ".($one+$two); //不能访问
如果在函数外部需要调用函数内部的变量值,必须通过return指令,来将其值传回至主程序区块以做后续处理
(2)全局变量
全局变量也成为外部变量,是在函数外部定义的,它的作用域为从变量定义开始,到本程序文件的末尾。和其他编程语言不通,全局变量不是自动设置为可用的。在PHP中,由于函数可以视为单独的程序片段,所以局部变量会覆盖全局变量的能见度,因此在函数中并无法直接调用全局变量。如下所示:
$a = 100;
$b = 100;
/**
用于测试在函数内部不能直接使用全局变量
**/
function demo(){
$c = $a + $b;
echo $c;
}
demo(); //$c不能输出
函数中若要使用全局变量,必须要使用globla关键字定义目标变量,以告诉函数主体此变量为全局变量。如下所示
例一:
$a = 100;
$b = 200;
function demo(){
global $a,$b;
$c = $a + $b;
echo $c;
}
demo(); //300
例二、
$a = 100;
$b = 200;
function demo(){
$GLOBALS['c] = $GLOBALS['a'] + $GLOBALS['b'];
}
demo();
echo $c; //300
(3)静态变量
局部变量从存储方式上可以分为动态存储类型和静态存储类型。函数中的局部变量,如不专门声明为static存储类型,默认都是动态的分配存储空间的。其中的内部动态变量在函数调用结束后自动释放。如果希望在函数执行后,其内部变量依然保存在内存中,应使用静态变量。在函数执行完毕后,静态变量并不会消失,在所有对该函数的调用之间共享,即在函数再次执行时,静态变量将继续前次的结果继续运算。并且尽在脚本的执行期间函数第一次被调用时被初始化。要声明函数变量为静态的,用关键字static。
代码示例:
function test(){
static $a = 0;
echo $a;
$a++;
}
test(); //第一次运行,输出0
test(); //第二次运行,输出1
test(); //第三次运行,输出2
在上例中,将函数test中的局部变量$a,使用static关键字声明为静态变量,并赋初值为0.函数在第一次执行四,静态变量$a经运算后,从初值0变为1.当函数第一次执行完毕后,静态变量$a并没有被释放,而将结果保存在静态内存中。第二次执行时,$a在内存中获取上一次计算的结果1,继续运算,并将结果2存于静态内存空间中。以后每次函数执行时,静态变量将从自己的内存空间中获取前次的存储结果,并以此为初值进行计算。
7、声明及应用各种形式的PHP函数
- 引用参数的函数
PHP中默认是按值传递参数,而且函数的参数也属于局部变量,所以即使在函数内部改变参数的值,它也不会改变函数外部的值。函数为子程序,调用函数的程序可以成为子程序。父程序直接传递指定的值或是变量给函数使用。由于所传递的值或变量,与函数里的数值分别存储于不通的内存区块,所以如果函数对所导入的数值做了任何变动,并不会对父程序造成直接影响。如下所示:
按值传递
/**
*@param int $arg 需要一个整型值参数
**/
function test($arg){
$arg = 200;
}
$var = 100; //在父程序中声明一个全局变量$var
test($var); //调用test函数,并将变量$var的值传给函数的参数$arg
echo $var; //输出100,$var的值没有发生改变
按引用传递
function test(&$arg){ //$arg 为引用参数
$arg = 200;
}
$var = 100;
test($var);
echo $var; //输出200,$var的值在函数中修改变量$arg时被修改
在上面的程序中,调用test()函数时,并不是将全局变量$var的值传递给函数test()。课看到,在test()函数的定义中,使用了引用符号“&”指定变量$arg为按引用传递方式。在函数体中对变量$arg指定了新值200,由于按引用方式会修改外部数据,所以外 部变量$var的值也一起被修改为200.调用函数结束后,可以看到变量$var的输出值为200.
可变个数参数的函数
代码示例一:
/**
*声明一个函数,用于打印参数列表的值
*虽然没有声明参数列表,但可以传入任意个数,任意类型的参数值
**/
function more_args(){
$args = func_get_args(); //将所有传递给脚本函数的参数当做一个数组返回
for($i=0;$i<count($args);$i++){
echo $args[$i] . "<br/>";
}
}
more_args("one","two","three");
输出结果:one two three
8、回调函数####
所谓的回调函数,就是指调用函数时并不是传递一个标准的变量作为参数,而是将另一个函数作为参数传递到调用的函数中。为什么使用回调函数呢?因为通过参数的传递可以改变调用函数的执行行为,但有时仅将一个值传递给函数能力是有限的,如果可以将一个用户自定义的“执行过程”传递到函数中使用,就大大增加了用户对函数功能的扩展。
1、变量函数
变量函数也称为可变函数。如果一个变量名后面有圆括号,PHP将寻找与变量的值同名的函数,并且将尝试执行它。
function one($a,$b){
return $a + $b;
}
function two($a,$b){
return $a*$b + $a*$b;
}
$result = "one";
echo $result(2,3); //输出5
在上例中声明两个函数。将函数名以字符串的方式赋给变量$result,然后使用变量名$result后面加上圆括号并传入两个整型参数,就会寻找与变量$result的值同名的函数。大多数函数都可以将函数名赋值给变量,形成变量函数。但变量函数不能用于语言结构,例如echo(),print(),isset(),empty(),include(),require()及类似的语句。
2、使用变量函数声明和应用回调函数
如果要自定义一个可以回调的函数,可以选择使用变量函数帮助实现。在定义回调函数是,函数的声明结构是没有变化的,只要声明的参数是一个普通变量即可。但在函数的内部应用这个参数变量时,如果加上圆括号就可以调用到和这个参数值同名的函数了,所以为其传递的参数一定要是另一个函数名称字符串中才行。使用回调函数的目的是可以将一段自己定义的功能传到函数内部使用。
代码示例:
/**
*声明回调函数filter,在0-100的整数中通过自定义条件过滤不要的数字
*@param callback $func 需要传递一个函数名称字符串作为参数
*/
function filter($func){
for($i=0;$i<=100;$i++){
//将参数变量$func加上一个圆括号$func(),则为调用和变量$func值同名的函数
if($func($i)) continue;
echo $i . "<br/>";
}
}
/**
*声明一个函数a,如果参数是3的倍数就返回true,否则返回false
*@param int $num 需要一个整数作为参数
*/
function a($num){
return $num%3 == 0;
}
/**
*声明一个函数b,如果参数是一个回文数(翻转后还等于自己的数)返回true,否则返回false
*/
function b($num){
return $num == strrev($num);
}
filter("a");
echo '------------------<br/>';
filter("b");
3、借助call_user_func_array()函数自定义回调函数
虽然可以使用变量函数去声明自己的回调函数,但最多的还是通过call_user_func_array()函数去实现。函数call_user_func_array()时PHP中的内置函数。
代码示例:
function fun($msg1,$msg2){
echo '$msg1=' . $msg1;
echo '<br/>';
echo '$msg2=' . $msg2;
}
/**
*通过系统函数call_user_func_array()调用函数fun(),第一个参数为函数fun()的名称字符串,第二个参数则是一个数组,每个元素之会按顺序传递给调用的fun()函数参数列表中
*/
call_user_func_array("fun","a","b");
4、类静态函数和对象的方法回调
/**
*声明一个类Demo,类中声明一个静态的成员方法
*/
class Demo{
static function fun($msg1,$msg2){
echo '$msg1=' . $msg1;
echo '<br/>';
echo '$msg2=' .$msg2;
}
}
/*声明一个类Test,类中声明一个普通的成员方法*/
class Test{
function fun($msg1,$msg2){
echo '$msg1=' .$msg1;
echo '<br/>';
echo '$msg2=' .$msg2;
}
}
/**
通过系统函数call_user_func_array()调用Demo类中的静态成员方法fun(),
回调类中的成员方法:第一个参数必须使用数组,并且这个数组需要指定两个元素,
第一个元素为类名成字符串,第二个元素则是该类中的静态方法名称字符串。
第二个参数也是一个数组,这个数组中每个元素值会按顺序呢传递给调用Demo类中的fun()方法参数列表中
*/
call_user_func_array(array("Demo","fun",array("a","b"));
/**
通过系统函数call_user_func_array()调用Test类的实例对象中的成员方法fun(),
回调类中的成员方法:第一个参数必须使用数组,并且这个数组需要指定两个元素。
第一个元素为对象引用,第二个元素则是该对象中成员方法名称字符串。
第二个参数也是一个数组。
*/
call_user_func_array(array(new Test(),"fun"),array("a","b");
9、递归函数####
递归函数即自调用函数,在函数体内部直接或间接的调用自己,即函数的嵌套调用是函数本身。通常在此类型的函数体之中会附加一个条件判断叙述,以判断是否需要执行递归调用,并且在特定条件下终止函数的递归调用动作,把目前流程的主控权交回上一层函数执行。因此,当某个执行递归调用的函数没有附加条件判断叙述时,可能会造成无限循环的错误情形。
函数递归调用最大的好处在于可以精简程序中的繁杂重复调用程序,并且能以这种特性来执行一些较为复杂的运算动作。
代码示例:
function test(){
echo $n . "  ";
if($n>0){
test($n-1);
}else{
echo "<-->";
}
echo $n . "  ";
}
10、使用自定义函数库####
require()与include()
require()语句的性能与include()相类似,都是包括并运行指定文件。不同之处在于,对include()语句来说,在执行文件时每次都要进行读取和评估;而对于require()语句来说,文件只处理一次(实际上,文件内容替换了require()语句)。这就意味着如果可能执行多次的代码,则使用require()效率比较高。另一方面,如果每次执行代码时是读取不同的文件,或者有通过文件迭代地循环就使用include()语句。