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); // 112、形参与实参的个数的关系
如果形参、实参没对应上
比如实参少于形参,函数有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自带函数(感觉这个很多,字符串函数、数组函数等等一大堆)
