[TOC] # 函数的定义 > 函数是什么? 函数(`function`)是一段完成指定任务的已命名代码块。函数可以遵照给它的一组值或参数完成特定的任务,并且可能返回一个值。在PHP中有两种函数:`自定义函`数与`系统函数`。 函数的优越性: * 控制程序设计的复杂性 * 提高软件的可靠性 * 提高软件的开发效率 * 提高软件的可维护性 * 提高程序的重用性 # 自定义函数 #### 自定义函数语法格式: 创建函数 ``` function 函数名称([参数1 [,参数2 [,…]]]){ 程序内容叙述(也叫函数体); [return 返回值;] //如需函数有返回值时使用 } ``` 调用函数: ``` 函数名称([参数1 [,参数2 [,…]]]; ``` ###### 1.自定义函数的名称: 它是函数在程序代码中的识别名称,函数名可以是以字母或下划线开头后跟零个或多个字母、下划线和数字的任何字符串。函数名不区分大小写。命名函数时不可使用已声明的函数,或PHP内建的函数名称。 ###### 2.参数: 所谓的参数就是用来把数值由函数外部传入函数体中,并用来加以运算处理。参数之间用" ,"号隔开。当函数不需要任何数值传入时,可以省略参数。 ###### 3.返回值: 当调用函数时需要它返回一些数值,那么就要函数体中用return语句实现。格式如下: ``` return 返回值; //返回值也可以是一个表达式 exit(); //无返回值 void ``` 实例: ``` <?php echo "用函数求累加:<br>"; function test($a) { $sum=0; for($i=0;$i<=$a;$i++) $sum+=$i; return $sum; } echo "50的累加是:".test(50)."<br>"; echo "100的累加是:".test(100)."<br>"; ?> ``` 在PHP中,函数可以在被调用之前定义,也可以在被调用之后定义。 `function_exists()` - - 判断函数是否存在。 # PHP变量的范围 #### 变量的范围 当主程序调用函数时,PHP 会暂时停止目前主要程序流程的运行,并传递必要的运算参数给目标函数使用,以执行函数的程序码片段。 在函数执行结束后,函数会回传执行结果所得的数值,并将执行流程转回原本主程序中断的地方,继续执行运作。 ####变量的能见度 所谓变量的能见度,意指变量在程序中的可作用范围。当一个变量执行赋值动作后,会随着声明局部的差异,而有不同的作用范围。大致上来说变量会依据声明的局部分为下列两种:**局部变量**和**全局变量** #### 局部变量(内部变量) 在函数之中声明的变量就是局部变量,并且该变量只有在函数范围之中才能加以使用。如果其它程序局部需要调用使用该变量值时,必须透过「return」指令,来将其传回至主程序区块以作后续处理。 ``` <?php $a=0; function print_A(){ $a = 3; //定义局部变量 echo "在函数中显示局部变量 a 值: $a <p>"; return $a; } $b = print_A(); echo "在函数外显示局部变量 b 值: $b <br>"; echo $a; ?> ``` #### 全局变量 在函数范围之外所声明的变量就是全局变量。由于函数可以视为单独的程序片段,所以局部变量会复盖全局变量的能见度,因此在函数中并无法直接调用使用全局变量。 函数中若要使用全局变量时,必须要利用`global`关键字定义目标变量,以告诉函数主体此变量为全局。 ``` <?php $A="Hello !!"; //定义全局变量 function print_A() { //定义函数 print_A() global $A; //利用 global 关键字声明变量 A 为全局变量 echo $A; } print_A(); ?> ``` 也可以使用预定义的全局变量数组`$GLOBALS`.这是一个特殊变量在程序运行时自动创建。格式:`echo $GLOBALS["A"];` > **注意事项** 在函数中声明全局变量时,其名字要与全局变量一致 通过unset($var)可以手动删除变量,变量会在内存中被释放,也就不在全局作用域中了。 使用require与include包含不会影响作用域 通过参数列表传递给函数的变量,对于函数来说是局部变量,除非在传递时带有&引用符号 #### 静态变量 静态变量只存在于函数作用域内。一般的函数内变量在函数结束后会释放,比如局部变量,但是静态变量却不会。就是说,下次再调用这个函数的时候,该变量的值会保留下来。 只要在变量前加上关键字static,该变量就成为静态变量了。 ``` <?php function test() { static $nm = 1; $nm = $nm * 2; print $nm."<br />"; } // 第一次执行,$nm = 2 test(); // 第一次执行,$nm = 4 test(); // 第一次执行,$nm = 8 test(); ?> ``` # 声明及应用各种形式的PHP函数 > 无论是使用系统函数还是自定义的函数,我们都要可通过如下函数的三要素来了解一个函数: * 函数的功能描述 * 函数的参数 * 函数的返回值 #### 常规参数的函数 常规参数的函数格式说明: ``` string example(string name,int age,double height) ``` 所谓的常规参数的函数,就是实参和形参应该个数相等、类型一致。就像C或Java等强类型型语言。 上面函数有三个参数,调用时传递的参数个数和顺序必须一致。 ``` string chr(int $ascii) //返回指定的字符 float ceil(float $value) //进一法取整 array array_combine(array $keys,array $values)//合并一个数组 string implode(string $glue,array $pieces) ``` #### 伪类型参数的函数 伪类型参数的函数格式说明: ``` mixed funName(mixed $a, number $b, callback $c) ``` PHP是弱类型语言,不仅在声明变量时不需要指定类型,当然在声明函数时也不需要指定类型,所以在PHP中函数的每个参数,都可以为其传递任意类型的值。 三种伪类型: `mixed`、`number` 和 `callback`。 ``` bool empty(mixed $var) //检查一个变量是否为空 bool usort(array &$array,callback $cmp_function) //使用用户自定义的比较函数对数组中的值进行排序 number abs(mixed $number) //绝对值 ``` #### 引用参数的函数 引用参数的函数格式说明: ``` void funName(array &args) ``` 相对于按值传递模式,并不会将父程序中的指定数值或目标变量传递给函数,而是把该数值或变量的内存储存区块相对地址导入函数之中。因此当该数值在函数中有任何变动时,会连带对父程序造成影响。 > 注意:如果在函数的形参中使用"&"修饰的参数,在调用该函数时必须传入一个变量给这个参数,而是不能传递一个值。 ``` <?php //使用常规参数传值 function test($arg) { $arg = 200; //在函数中改变参数$a的值为200 } $var = 100; //在父程序中声明一个全局变量$var,初值为100 test($var); //调用test函数,并将变量$var的值100传给函数的参数$arg echo $var; //输出100。$var的值没有变化 //使用"&"引用参数传值 function test( &$arg ) { $arg = 200; //改变参数$a的值为200,$arg是引用参数,外部变量$var也被修改 } $var = 100; //在父程序中声明一个全局变量$var,初值为100 test($var); //调用test函数,并将变量$var的引用传给函数的参数$arg echo $var; //输出200。$var的值在函数中修改变量$arg时被修改 ?> ``` #### 默认参数的函数 默认参数("[ ]"中的)的函数格式说明: ``` mixed funName(string name [,string value [,int num]]) ``` 在php中,支持函数的默认方式调用。如果在调用函数时没有指定参数的值,在函数中会使用参数的默认值。 > 注意:默认参数必须列在所有没有默认值参数的后面。 ``` <?php /** 自定义一个函数名称为person,用于打印一个人的属性 @param string $name 人的名子属性字符串,默认值为"张三" @param int $age 人的年龄属性,默认值为20 @param string $sex 人的性别属性,默认值为"男" */ function person( $name="张三", $age=20, $sex="男" ){ echo "我的名字是:{$name}, 我的年龄为:{$age}, 性别: {$sex} <br>"; } person(); //在调用函数时三个参数都没有传值,全部使用默认参数 person("李四"); //第一个默认参数被传入的值覆盖,后两个参数使用默认参数 person("王五", 22); //前两个默认参数被传入的值覆盖,最后一个使用默认参数 person("贾六", 18, "女"); //在调用函数时,三个默认参数都被传入的值覆盖 ?> ``` #### 可变个数参数的函数 可变个数参数的函数格式说明: ``` mixed funName(string arg1 [,string ...] ) ``` 通常用户定义函数时,设置的参数数量是有限的。如果希望函数可以接受任意数量的参数,需使用以下函数: ``` func_get_args() //返回一个数组,包含所有参数 func_num_args() //返回参数总数 func_get_arg() //接收一个数字参数,返回指定参数 ``` ``` <?php /** 声明一个函数more_args(),用于打印参数列表的值 虽然没有声明参数列表,但可以传入任意个数,任意类型的参数值 */ function more_args() { $args = func_get_args(); //将所有传递给脚本函数的参数当做一个数组返回 for($i=0; $i<count($args); $i++) { //使用for循环遍历数组$args echo "第".$i."个参数是".$args[$i]."<br>"; //分别输出传入函数的每个参数 } } more_args("one", "two", "three", 1, 2, 3); //调用函数并输入多个参数 function more_args() { for($i=0; $i<func_num_args(); $i++) { //使用for循环遍历数组$args echo "第".$i."个参数是".func_get_arg($i)."<br>";//分别输出传入函数的每个参数 } } more_args("one", "two", "three", 1, 2, 3); //调用函数并输入多个参数 ?> ``` #### 回调函数 回调函数格式说明: ``` mixed funName(callback arg) ``` 所谓回调函数,就是指调用函数时并不是传递一个标准的变量作为参数,而是将另一函数作为参数传递到调用的函数中。 1. 变量函数 2. 使用变量函数声明和应用的回调函数 3. 借助call_user_func_array()函数自定义回调函数 4. 类静态函数和对象的方法回调 ###### 变量函数 ``` <?php /** 声明第一个函数one, 计算两个数的和 @param int $a 计算和的第一个运算元 @param int $b 计算和的第二个运算元 @return int 返回计算后的结果 */ function one( $a, $b ) { return $a + $b; } /** 声明第二个函数two, 计算两个数的平方和 */ function two($a, $b) { return $a*$b + $b*$b; } $result = "one"; //将函数名"one"赋给变量$result, 执行$result()时则调用函数one() //$result = "two"; //将函数名"two"赋给变量$result, 执行$result()时则调用函数two() echo "运算结果是:".$result(2, 3); //变量$result的函数名值,就调用哪个函数 ?> ``` ###### 回调函数 ``` <?php // 声明回调函数filter, 在0-100的整数中通过自定义条件过滤不要的数字 function filter( $fun ) { for($i=0; $i <= 100; $i++) { //将参数变量$fun加上一个圆插号$fun(), 则为调用和变量$fun值同名的函数 if( $fun($i) ) continue; echo $i.'<br>'; } } //声明一个函数one, 如果参数是3的倍数就返回true, 否则返回false function one($num) { return $num%3 == 0; } // 声明一个函数two, 如果参数是一个回文数(翻转后还等于自己的数)返回true, 否则返回false function two($num) { return $num == strrev($num); } filter("one"); //打印出100以内非3的倍数,参数"one"是函数one()的名称字符串,是一个回调 echo '--------------------<br>'; filter('two'); //打印出100以内非回文数,参数"two"是函数two()的名称字符串,是一个回调 ?> ``` ###### 借助call_user_func_array()函数自定义回调函数 ``` <?php /** 声明一个函数fun(), 功能只输出两个字符串,目的是作为call_user_func_array()回调参数 @param string $msg1 需要传递一个字符串作为参数 @param string $msg2 需要传递另一个字符串作为参数 */ function fun($msg1, $msg2) { echo '$msg1 = '.$msg1; echo '<br>'; echo '$msg2 = '.$msg2; } /** 通过系统函数call_user_func_array() 调用函数fun() 第一个参数为函数fun()的名称字符串 第二个参数则是一个数组,每个元素值会按顺序传递给调用的fun()函数参数列表中 */ call_user_func_array('fun', array('canshu1', 'canshu2')); ?> ``` ###### 匿名函数 匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。 ``` <?php $greet = function($name){ printf("Hello %s\r\n", $name); }; $greet('World'); $greet('PHP'); ?> ``` ###### 递归函数 * 所谓的函数递归调用,就是函数可以在其声明的执行叙述之中调用执行自己。 * 通常在此类型的函数之中会附加一个条件判断叙述,以判断是否需要执行递归调用,并且在特定条件下终止函数的递归调用动作,把目前流程的主控权交回上一层函数执行。因此当某个执行递归调用的函数,没有附加条件判断叙述时可能会造成无限循环的错误情形. * 函数递归调用最大的好处在于可以精简程序中繁杂重复调用程序,并且能以这种特性来执行一些较为复杂的运算动作。 ``` <?php /** 声明一个名称为test的函数,用于测试递归 $param int $n 需要一个整数作为参数 */ function test( $n ) { //声明一个名为test的函数,有一个参数 echo $n."  "; //在函数开始处输出参数的值和两个空格 if($n>0){ //判断参数是否大于0 test($n-1); //如果参数大于0则调用自己,并将参数减1后再传入 }else{ //判断参数不大于0 echo " <--> "; //输出分界字符串 } echo $n."  "; //在函数结束处输出参数的值和两个空格 } test(10); //调用test()函数将整数10传给参数 ?> ``` #### 使用自定义函数库 代码重用: * 通过重复使用已有的代码,提高开发效率,降低成本 `include( )`和`require( )` 函数。 * require( )将一个文件在预处理期间被导入,像把该文件粘贴到使用函数的地方。 * include( )与require ( )几乎等价,区别在于在脚本执行时包含,当处理失败时,include( )产生一个警告而require( )则导致一个致命错误。 > ##include_once( )和require_once( )函数## 两个函数在脚本执行期间包括并运行指定文件。与include( )语句及require( )类似,唯一区别是如果该文件中的代码已经被包括了,则不会再次包括,只会包括一次。这两个函数应该用于在脚本执行期间同一个文件有可能被包括超过一次的情况下,你想确保它只被包括一次以避免函数重定义,变量重新赋值等问题。 *** >Have a try 使用循环语句实现下列代码:要求时间的每个图像(要求图像的都使用函数定义) ![Paste_Image.png](http://upload-images.jianshu.io/upload_images/4630996-efc7b34977a84e42.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)