PHP 函数
一、函数的概念
函数是非常重要的概念,无论是C语言这样的面相过程式的程序,还JAVA这种面相对象式的程序都离不开函数,当然面相对象的时候,函数不叫函数叫方法。
1、概念
函数是有特定功能的代码。
可以把某些常用而特定的功能写一个函数,需要实现这个功能时,可以调用这个函数。
从而达到重用代码和简化开放的目的。
2、从编程的角度来理解函数
下面是最简单的一个函数
/** * 从编程的角度看 * 把若干语句,封装在一块,起一个名字, * 下次根据名字来调用这个封装的块,就可以称之为函数。 * */ function QiCha(){ echo '把水灌进水壶,烧开<br/>'; echo '把茶叶放进茶杯<br/>'; echo '往茶杯冲开水<br/>'; echo '端上茶杯<br/>'; } QiCha();
3、从数学的角度来理解函数
再通过数学的角度来理解函数,高中的时候学过函数
数学里面函数的概念:函数是变量之间的关系
比如:y = 2 * x;
当x=1,则算出y=2
当x=3,则算出y=6
……
……
我们可以看出,y与x之间,存在一种关系,
返回的y是根据x的值乘以2
也就是说y这个量和x这个量,他们之间有关系,形成了函数
写一个“真实男友数量推测机”
/** * 问男生的时候:你谈过几个女朋友 * 男生真实谈过的女朋友 == 他说的个数/3 * 女生真实谈过的男朋友 == 她说的个数*3 * * 推测一个女生交过男朋友的真实数量 * $real = $say * 3; * * 她说的个数的三倍 * 给我一个数,我帮你算出一个3倍的属性 —— 这样一个量与量的关系 * * 先给函数一个值,然后函数乘以3,函数再还给我,仔细看这三个过程 * * 此时的函数,像不像一个豆浆机 * 入口处输入:黄豆 * 机器内:搅拌黄豆 * 出口:豆浆 * */ function she($say){ // 参数是入口 $real = $say * 3; // 函数体是加工 return $real; // 出口 } $num = 5; echo '大s说她谈过' ,$num, '次恋爱<br/>'; echo '推测她真实谈过' ,she($num), '次恋爱';
通过两个例子学了函数的概念
1). 第一个例子:从编程的角度学函数,从编程的角度,把若干语句封装在一块,起一个名字,就可以来调用了
2). 第二个例子:从数学的角度,其实第二个例子更能说明函数的本质,有入口,有处理,有出口。然后给喊传一个参数,函数就给处理了
注意,函数调动会有一返回值,返回的值就是return的值
二、函数的声明语法
最简单的函数声明
写一个函数名包装几个语句,可以没有参数
function foo(){ }
也可以带有参数
可以有1个或N个参数,然后处理完参数可以return一个值,也可以不return值
function foo($arg1, $arg2, $arg3){ // return 值; }
函数就是一个加工机器
输入黄豆,加工,return 豆浆
输入苹果,加工,return 罐头
输入淑女,加工,return 辣妹
函数声明的语法,可以是最简单的包装几个语句,复杂一点可以带几个参数,处理完参数给我们return值,也可以不return值。
三、函数的调用
函数以其名称来调用
function foo(){ echo 'foo'; } foo(); // foo
如果函数指定了参数,还需要传参
function bar($num){ echo $num * 10; } // bar(); // 没有传参数,这样调用就出错了 bar(9); // 90
四、函数的命名规范
函数的命名规范和变量一样,以字母、数字、下划线组合,但数字不能开头
函数和变量不一样的地方,函数名字不区分字母的大小写。
以后学面相对象的时候,方法(理解成函数)也是不区分字母小写的
function foo(){ echo 'foo'; } FOO(); // 函数的名字是不区分大小写的
五、形参与实参的概念
长方形面积的公式:
小学时:长方形面积 = 长 * 高(三年级听不懂,听成"长城高"?)
初中时:s = a * b(s表示面积,a和b表示长和宽)
高中时:s = α * β(阿尔法 乘以 贝塔)
分析这三个公式,变的是什么,不变的是什么?
用来表示矩形两个边的“名称”变了
长 宽
a b
α β
不变的是关系,既无论用哪种方式,面积始终等于长乘宽,这层关系。
/** * 参数只是一个变量名,在函数体内发挥作用,参数的值来自于调用时,传递的值。 * * 函数内部声明了2个变量,$长、$宽 * 1. 把接收到的值,按照顺序分别赋给形参 * 此时形参已经有值了 * 2. 函数体执行 * 3. 最后返回 * */ function 面积($长, $宽){ // $长,等于传过来的10 // $宽,等于传过来的8 // 然后10 * 8 的结果return回来 return $长 * $宽; } echo 面积(10, 8); // 80 /** * function s($a, $b){ * * // 把外界传的的值,赋给函数声明的参数变量 * // $a = 10; * // $b = 8; * * return $a * $b; * } * * 调用 s(10, 8); * 无论,参数叫($a, $b),还是叫($长, $宽) * 都没关系,因为参数的计算关系没有变 * * 一定要注意: * 外界的值传给了,函数参数对应的变量, * 而函数的参数($a, $b)、($长, $宽)都是在函数体内发挥的作用 * */ function s($a, $b){ return $a * $b; } echo s(10, 8); // 80
看下面这个例子
/** * she函数的调用的时候 * 传的参数$num,真正用的是什么? * 用的是$num的值 * * 函数先在函数体内声明$say变量 * 然后再把$num的值,赋给$asy * 执行 * 返回 * */ function she($say){ // 模拟执行如下 // $say = $num; // $num就是把自己的值读出来,赋给了$say // 而且$say还是在函数内部发挥的作用 $real = $say * 3; return $real; } $num = 5; echo she($num); // 15
声明函数时的参数,叫形式上的参数 ——> 形参
调用函数时的参数,叫实际传递的参数 ——> 实参
说白了:
形参在函数体内提供的是"变量名"
实参在函数体内提供的是"值"
考考你,对形参、实参理解了没有
function foo($num){ $num +=1; $num *=2; $num /=3; $num +=999; return $num; } $price = 100; echo foo($price),'<br/>'; // 1066.3333333333 echo $price; // 100 /** * $price根本就没变还是100 * 因为,在函数运算时候,$price的"值"传递给了$num * 因此,函数体内的$num,无论怎么变,和$price无关了 * */
六、参数的传值详解
形参与实参的顺序
形参与实参的个数关系
参数的默认值
1、形参与实参的顺序
/** * 函数在调用的过程中 * 实参,形参,从左 -> 到右,严格的逐一对应(对号入座), * 然后实参的值,挨个儿赋给形参 * 1 赋值给 $x * 2 赋值给 $y * 3 赋值给 $z * */ function foo($x, $y, $z){ return 2*$x + 3*$y + $z; // 执行:2*1 + 3*2 + 3 } echo foo(1, 2, 3); // 11
2、形参与实参的个数的关系
如果形参、实参没对应上
比如实参少于形参,函数有3个形参,只传2个实参给函数
function foo($x, $y, $z){ return 2*$x + 3*$y + $z; } echo foo(1, 2); // 报错 Fatal error: …… echo 'PHP7中不会往下执行,这行是看不到的';
这次是实参多余形参,会是怎么样呢?
function foo($x, $y, $z){ return 2*$x + 3*$y + $z; // 执行:2*1 + 3*2 + 3 } echo foo(1, 2, 3, 4, 5, 6, 7); // 11 /** * 输出 11 * 因为实参对号给形参赋值的时,后面多出来的实参,将会被忽略掉,没有其它副作用 * */
3、参数的默认值
/** * 介绍自己的国籍: * 在国内基本都是中国人,就不需要介绍自己的国籍 * 所以,要是说自己是某国人,就说我来自某国 * 如果不指明自己的国籍,就默认为中国人 * * ps: country 和 nationality国家与国籍 * */ function intro($country = '中国'){ return '我来自'.$country; } echo intro(),'<br/>'; // 我来自中国 echo intro('美国'),'<br/>'; // 我来自美国 echo intro('日本'),'<br/>'; // 我来自日本
有默认值的参数,并不能改变,实参与形参,严格按顺序赋值的原则。
$x已经有默认值了,就传两个值行吗?
function sum($x=4, $y, $z){ return 2 * $x + 3 * $y + $z; } sum(5, 6); // 报错 Fatal error /** * 分析: * 实参与形参,严格按顺序赋值的原则不会变 * 5给了$x * 6给了$y * 因此没有值给$z * */
想一想,既然有了默认参数,调用时,又没能少传实参?
怎么才能少传一个实参,利用上默认的参数?
sum(, 5, 6); 用逗号把第一个参数空出来,这样也不行语法错误
如果参数有默认值,要把该参数,写到最后面
function sum($x, $y=3, $z=4){ return $x + 2 * $y + 3 * $z; } echo sum(1),'<br/>'; // 19 echo sum(1, 2); // 17
总结
1). 函数可以设置默认值
有默认值的参数,一般在后面
2). 如果某个有默认值的形参,他对的位置上传了实参,
那么,实参的值将要覆盖默认值。
七、函数与变量的作用域
$num = 5; function t(){ $num = 9; } t(); echo $num,'<br/>'; // 5 /*** * 默认状况下: * 1.函数运行时,有其独立的变量空间。 * 2.函数体内的变量,与外界的变量,无关。 * 3.即使是变量的名字相同,也无关 * 4.所以打印输出 5 * */
当函数调用时候,系统会申请一块独立的“内存空间”
函数体内的变量,在其独立的“调用空间”里,与外界的变量无关
函数调用结束后,申请的独立的“调用空间”,就释放掉了
下次,再调用,再申请,函数还得“从头初始化”
函数内部的叫:局部变量
函数外部的叫:全局变量
$num = 5; function t(){ $num = 9; } t(); // 再写一个函数t2 function t2(){ echo $num; // Notice: Undefined variable: num in } t2(); /** * 函数是独立的,函数请求执行一次,就申请一块内存空间执行一次,执行完后立即就释放掉 * 释放掉了,下次在调用,再申请空间,再重新初始化 * * 1. 因此t2()的调用,不关t函数的事 * 2. t2的函数体内,没有$num变量 * 3. 默认情况下,函数也不会去全局找$num * 3. 所以打印提示,未定义的变量 Notice: Undefined variable * */
php和js的比较
var num = 5; function t(){ // var num; document.write(num); } t(); // 5 /** * 在js中,有作用域链的概念,在函数内找不到变量num,就会往外层寻找。 * 在PHP中,则不会跑到外层去寻找。 * * 上面只是说了现象,其实没有什么不同 * JS中函数中访问的变量num,是没有声明就直接赋值的,所以num是属于全局的变量,在函数里面是可以访问到全局 * 如果在函数里面声明 var num; 结果就不一样了, * 结果打印undefined * */
简单说,PHP函数内的变量,就局限在函数体内。
再看一道题
function t3(){ $age = 19; $age += 1; echo $age,'<br/>'; } t3(); // 20 t3(); // 20 t3(); // 20 /** * 函数一调用,就为为他开辟一块内存空间 * 函数调用完,空间立即释放掉 * 下次再调用,再申请独立的空间,从头初始化 * …… * */ // t3(),'<br/>'; 函数后面加 <br/> 会报错
小例子:
小小的计算器,只计算加、减、乘、除
function calc($num1, $act, $num2){ $res = null; switch($act){ case '+': $res = $num1 + $num2; break; case '-': $res = $num1 - $num2; break; case '*': $res = $num1 * $num2; break; case '/': if($num2 == 0){ echo '0不能做除数'; // 这里判断一下,如果是0,提示一下,直接break,不往下走了 break; } $res = $num1 / $num2; break; default: $res = null; break; } return $res; } echo calc(3, '+', 2),'<br />'; // 5 echo calc(3, '*', 7),'<br />'; // 21 echo calc(3, '/', 0),'<br />'; // 0不能做除数
下面逻辑明白,但是运算符是字符串
function calc($num1, $act, $num2){ if($act != '+' && $act != '-' && $act != '*' && $act != '/'){ echo '不等于加减乘除,操作符有误,直接结束掉'; exit; // 先暴力结束,其它更好的办法,明天再说 } // var_dump($act); return $num1 . $act . $num2; } echo calc(3, '+', 2),'<br />'; // 3+2 echo calc(3, '*', 7),'<br />'; // 3*7
八、函数执行权与交回
1、函数的执行权
function t(){ echo 'a<br/>'; echo 'b<br/>'; echo 'c<br/>'; } echo 'x','<br/>'; t(); echo 'z','<br/>'; // z是等到,t()函数运行结束后才运行 /** * 页面运行结果: * x * a * b * c * z * */
调用函数的时候,程序的执行权,进入到函数内部
程序的执行权,进入到函数内部之后,什么时候,交出来执行权呢?
先看一个复杂一点,三个函数的嵌套
function t3(){ echo 't3<br/>'; } function t2(){ echo 't2<br/>'; t3(); } function t1(){ t2(); echo 't1<br/>'; } t1(); /** * 根据大原则:调用函数的时候,程序的执行权,进入到函数内部 * 1. t1()调用执行,执行权来到t1函数体内,又执行了t2() * 2. t2()被调用了,执行权转的t2里面来了, * 输出 echo 't2<br/>' * 紧接着执行t3() * 3. 调用t3()。输出 echo 't3<br>'; * 4. 最后都执行完了,echo 't1<br>'; * * 打印的结果: * t2 * t3 * t1 * */
2、执行权的交回
function foo(){ echo 'a'; echo 'b'; echo 'c'; echo '<br/>'; } echo 'x','<br/>'; foo(); echo 'z','<br/>'; /** * 结果: * x * abc * z * */
通过这个结果,我们可以发现
当函数语句运行完之后,执行权就交回了
除了语句运行完毕,执行权交回,还有没有其它情况执行权交回?
有的,碰到rettrn之后,函数交回执行权
function bar(){ echo 'a'; return; echo 'b'; echo 'c'; echo '<br/>'; } echo 'x','<br/>'; bar(); echo 'z'; /** * 打印结果: * x * a * z * */
九、函数的返回值
求“和”函数
function sum($num1, $num2){ return $num1 + $num2; } $s = sum(3, 2); // 调用函数,调用函数要返回一个结果 // 结果,就是return的值 // sum(3, 2)返回的结果赋给变量$s echo $s; // 5
函数调用必有返回结果,return有返还的意思,return什么返回的就是什么
但是函数是可以没有return语句的,如果没有return语句返回什么?
function t(){ $num = 999; } $s = t(); var_dump($s); // NULL
还有一种情况,有的时候函数确实结束了,但有没有必要返回值,因此只写一个return
// 没有return任何值,没有值这种值叫NULL function t2(){ $num = 666; return; // 就写一个return echo 'aaaa'; } var_dump(t2()); // NULL
调用函数的返回值
1).返回return后面的值
2).如果没有return语句,或"return;"(空)
返回值是NULL
思考:
函数可不可以return回来2个值?
高中数学知识,函数是一种映射关系,一个具体的值,只可能算出一个结果
也就是经过了一次计算,不可能算出来两个值。一个算式是具体的,算出来的结果也是具体的。
函数的定义就已经决定,只可能return一个值。
return arr(1, 2); 数组是一个值,只不过是一个符合值。
function t3(){ return array('x',9); } $x = t3(); var_dump($x); // array(2) { [0]=> string(1) "x" [1]=> int(9) }
十、动态函数
函数的名字可以用变量来表示
PHP中变量可以是动态的,常量也可以是动态的,函数还可以是动态的
function wel(){ echo '欢迎<br/>'; } function love(){ echo '思密达<br/>'; } function cry(){ echo '呜呜<br/>'; } /** * 执行那个函数不一定 * 输入哪个函数名,就执行哪个函数 * * .php?func=wel * .php?func=cry * .php?func=love * */ if(isset($_GET['func'])){ $func = $_GET['func']; // echo $func,'<br/>'; // 输入哪个函数名,就执行哪个函数 if(function_exists($func)){ $func(); // 加个小括号来调用,则会把$func的值,当做"函数名"来调用该函数 } }else{ echo '没有传函数的名'; }
PHP的灵活之处,以后学面相对象时,"类"的名字也可以是变量
同样的操作在java里就要用反射
以后写框架的时候,就要用到这种强大特性
ps:PHP也可以用call_user_func
十一、引用赋值
$age = 19; function t($num){ // $age把值赋给$num,所以$age的值还是19 // $num = $age 相当于 $num += 5; } t($age); echo $age; // 19
下面看函数参数的“引用赋值”
形参前多了一个&符号,传的不再是传实参的值,而是传实参的地址
$age = 19; function foo(&$num){ // 多了一个&符号,此处的传参,传的不再是传形参的值,而传的是形参的地址 $num += 5; } foo($age); echo $age; // 24 /** * 这次的几个为什么是24呢? * * 是这样一个过程: * function foo(&$num){ * // $num = &age; * // 此时,函数内部的$num,也指向外部全局变量$age地址的空间上去了 * // $num变了,外面$age也变了 * $num += 5; * } * */
函数参数也是可以“引用赋值”
同时,我们也可以看到
函数内的局部变量,和全局上的变量
并不是谁都不会碰到谁,是有机会互相影响的,
比如:引用传参,以及超级全局变量
总结
下面是课程PPT的目录,与实际视频课程有点出入。
记录下来与实际视频课程内容,对比复习函数方面的知识点。
- 函数的概念
- 函数的封装与重用
- 函数的定义格式
- 函数的返回值
- 函数的命名规范
- 参数的传值方式
- 变量函数(应该是动态函数)
- 函数及函数中变量的作用域
- PHP自带函数(感觉这个很多,字符串函数、数组函数等等一大堆)