函数
基本使用
function 函数名(形参1,形参2, .......){ //函数体(代码块)}
1,没有返回值的函数,调用语句为独立语句。函数名(实参1,实参2,........);
2,具有返回值的函数,调用语句会掺杂在别的语句中,把该函数当做一个数据使用:
- 函数定义形式
- 函数调用形式
$v1 = 函数名();
$v1 = 函数名()*3+6;
echo 函数名();
echo 函数名()*3+6;
$v1 = 函数名2(函数名(),实参2);
- 函数调用流程分析
- 开始调用:实际参数传递数据给形式参数
- 程序执行流程进入到函数中(一个独立的空间),跟全局执行空间分离
- 按常规的程序逻辑执行函数中的代码
- 遇到return则终止函数运行,返回原来函数调用的位置
- 如果没有return,执行到函数结尾再返回到原来的函数调用的位置
函数参数
函数定义时:形式参数(形参)
- 一定为变量名
- 只在函数中有效
- 函数结束即销毁
调用函数时:实际参数(实参)
- 实际有意义的数据,可变量可常量
- 作用:将其赋值给形参
- 实参与形参一一对应
参数默认值
函数定义时形参可给定“默认值”,此时将该形参称为默认值参数
- 默认值不能是对象或资源类型
- 默认值只能是常量表达式或常量,但不能是变量
- 默认参数必须放在非默认值的右边
参数传值问题
如果实参为变量,则默认为值传递;否则实参为常量即简单赋值
当然,函数传值也存在引用传递:只需简单该一下形参的形式(作用:当形参改变时,对应引用传递的实参变量也改变且实参只能是变量)
function getArea(&$r1, $PI = 3.14){} //$r1为引用传递
参数的数量问题
- 函数的参数的数量可以是0个或多个,具体看实际情况
- 通常,形参和实参的数量一致
- 在有默认形参的基础上,实参可省略,即实参数量小于形参数量(但实参数量不得小于形参中非默认参数的数量,否则报错)
- 实际参数大于形参数量不报错
除此之外,还可以有一种特殊的处理函数参数的用法:自由参数(即定义时可以不给定形参,但调用时却又可以给定任何个数的实参)
系统中,var_dump()也有类似的用法:var_dump($v1)和var_dump($v1,$v2)都行
这种应用的实现得益于系统中的3个系统函数达到目的
func_get_args(); //获得一个系统所接收到的所有实参数据并返回一个数组
func_get_arg(n); //获得函数所接收到的第n个实参数据(从0开始)
func_num_args(); //传递的实参个数
结果为:
函数的返回值
通常,一个函数中使用return语句返回数据(直接数据,变量数据,表达式结果数据)
通常,函数返回的数据都是以“值传递”的形式返回:函数中变量的值“拷贝”一份,返回接收的位置。
当然,也可以让函数中的返回值以“引用传递”的方式返回,形式如下:
可以看出,引用传递的方式不太实用且只有实用静态变量时该引用传递才有意义
函数的其他形式
1,可变函数
可变函数,就是函数名“可变”--跟可变变量差不多
$str1 = "f1";
$v1 = $str1(3, 4); //即调用f1函数
实际应用中,常常需要根据“用户给定”的数据,来决定调用那个函数,比如:
function jpg(){处理jpg图片}
function png(){处理png图片}
function gif(){处理gif图片}
$fileName = get_fileName(){获取用户上传的图片名}
$houzhui = get_houzhui($fileName);
$houzhui();
这样可根据用户需要处理哪种类型的图片
示例验证
2,匿名函数
匿名函数:没有名字的函数,其有两种表现形式:
表现1:$f1 = function(){函数体;}//这里的匿名函数定义形式上没有名字,但其实将其赋值给变量$f1,跟可变函数类似。
表现2:调用其他函数(匿名函数,实参1,实参2,...),说明如下:
- 此形式的匿名函数只有定义的函数体(无函数名)
- 此形式的匿名函数只能作为其它函数调用时的参数(其他函数通常有特定用处)
- 此匿名函数会在调用其他函数的“中间”执行
此类函数并不多,其中一个为:call_user_func_array();
使用形式:call_user_func_array(匿名函数,数组),将数组作为该匿名函数的实参且能够return数据
变量的作用域
通常2个:全局作用域:函数外部范围使用;局部作用域:所定义的函数范围内(-php:局部和全局作用域不重叠;-js:全局作用域包括局部作用域)
实际还有2个:超全局作用域:在函数内外都可使用(预定义变量);静态局部作用域:也是局部,但数据能够在函数退出后不丢失。
局部访问全局变量的特定语法:
1,在局部范围内,可使用global关键字对全局变量进行一次“声明”,则该全局变量可使用.
语法:global $变量名;
声明:实际上,函数中的global语句,其实是创建了一个跟外部变量同名的局部变量,然后将其引用传递给该局部变量
2,在函数中,使用$GLOBALS超全局数组来引用(使用)全局变量:
$GLOBALS超全局数组的作用是用于存储所有全局变量的数据:变量名为下标,变量值为对应元素值
但通过$GLOBALS操作使用全局变量是直接操作而非引用,说明一旦在函数内unset,该全局变量立即销毁
3.可以使用$GLOBALS数组中添加元素即添加全局变量,类似于在局部范围内使用全局变量
全局访问局部变量的特定语法:
- 通过引用传递的方式向形参传递一个引用实参变量
- 使用函数的引用返回方式
- 函数中使用global关键字来首次引用一个全局变量,则函数结束后在全局范围就可以使用该变量
结果:
有关函数的系统函数
- function_exists():判断某个函数是否被定义过,返回布尔值
- func_get_arg(n):获得一个函数的第n个实参(n从0开始)
- func_get_args:获得一个函数的所有实参,结果是一个数组
- func_num_args:获得函数实参的个数
函数编程思想
递归思想(递归函数)
递归思想的一个基本形式:函数中存在语句调用本身。
递归所需两个条件:1,调用函数本身;2,结束条件即递归函数出口
案例:计算正整数n的阶乘
数学模型:n! = (n-1)! * n //关键找到递归模型
结束条件:n大于等于1 //从量化角度缩小
代码如下:
递归思想:
最初问题(n级问题)--》n-1级问题--》n-1-1级问题--》。。。--》已知问题
递推思想(迭代思想)
递推思想本身并不跟函数有直接关系(也可写在函数中)
基本思路:为了解决大问题。根据现实逻辑,如果能够找到同类问题的一个“最小问题”的答案,并且根据已知算法,又可以因此得到比最小问题大一级问题的答案,而且依次类推又可以得到再大一级问题的答案,最终得以解决最初的问题。
该思想过程依赖2个条件
- 可知同类最小问题的答案
- 大一级问题的答案可以通过小一级问题的答案经过简单运算规则得到(从小到大)
递推思想:从大到小,再回归到大
举例:求斐波那契数列的第n项的值
规则:某项的值是前两项的值的和。
前几项为:1,1,2,3,5,8,13,21,.....(前两项已知)
结果为:
递推算法:
最小问题--》最终问题(从小到大)
总结:
- 很多问题,用递归和递推都可以解决
- 有些问题只能用递归
- 两者都能用建议用递推(算法效率高很多)