函数的类型、参数与返回值
一、函数的基本语法语法
functionfunctionName(类型限定参数列表):返回值类型
{
}
案例:计算两个数之和。
functionsum(int$a,int$b):string
{
return$a+$b;
}
echo sum(1,2);// 3
二、函数的分类
2.1 命名函数命名函数自动提升到脚本顶部,在全局任何地方都能调用。
// 按函数名称调用
demo1('残破的蛋蛋');
// 声明一个demo1函数
functiondemo1($name){
echo"My name is ${name}.";
}
以上代码会输出:My name is 残破的蛋蛋.
2.2 匿名函数没有指定具体函数名称的函数叫匿名函数,也叫闭包函数。
$var=function(){
// TODO
}
以上声明的就是一个匿名函数,它需要把函数赋给一个变量,然后通过变量去调用。
$demo2=function(){
echo"Hello World!";
}
$demo2();// Hello World!
匿名函数通过变量调用,以上结果为:Hello World!。
三、函数的参数
3.1 必选参数functionperson1(string$name):string
{
return"Hello, ${name}!";
}
echo person1('残破的蛋蛋')."
";// Hello, 残破的蛋蛋!
echo person1(123)."
";// Hello, 123!
echo person1(true)."
";// 报错
上述第三次函数调用报错的原因是:当限定了传入的参数类型为字符串时,标量(单值)会自动转换成字符串,但是布尔型、数组、类是无法自动转换的。
3.2 可选参数在定义函数的时候声明了参数,如果在调用的时候没有指定参数或者是少指定了参数,那么就会出现缺少参数的报错。在PHP中,支持函数的默认方式调用,即为函数的参数指定一个默认值,在调用函数的过程中如果没有指定参数的值,那么在函数中会使用参数的默认值。
functionperson2(string$name,int$age=20,string$sex="男"){
echo"我的名字是:${name},年龄:${age}岁,性别:${sex}。
";
}
// 我的名字是:残破的蛋蛋,年龄:20岁,性别:男。
person2('残破的蛋蛋');
在上述案例中我们确实为person2()函数声明了三个参数,但是我们只传了一个参数,其他两个参数都使用的是默认值。当调用函数传参的过程中,实参和形参是按照参数传递的顺序一一对应的,如果实参个数少于形参,则后面的形参不会被传值。当使用默认参数时,必须放在非默认参数的后面,否则可能会导致函数不会按照预期的执行。
3.3 不定参数语法
functionfunctionName(...$args){
// TODO
}
functionperson3(){
// 获取传递给函数的所有变量数组
$args=func_get_args();
// 遍历每一个传入的参数
foreach($argsas$key=>$arg){
$num=$key+1;
echo"第${num}个参数是:${arg}
";
}
}
person3('残破的蛋蛋',30,'男');
// 第1个参数是:残破的蛋蛋
// 第2个参数是:30
// 第3个参数是:男
从PHP5.6以后,可以不使用func_get_args()函数获取可变参数,使用“…”运算符来实现可变长度的函数。
functionperson4(...$args){
print_r($args);
}
person4('残破的蛋蛋',30,'男');// Array ( [0] => 残破的蛋蛋 [1] => 30 [2] => 男 )
这是一个非常实用的功能,当一个函数的参数过多时,可以不用逐一地传递参数,实用可变参数就可以传参了。
四、函数的返回值
通常情况下,函数只允许有一个返回值,原则是“单值”返回的,如果想返回多值怎么办?那么只能在返回值的类型上打主意了,可以通过以下方法来操作。
4.1 返回一个数组functionsuccess():array
{
return['status'=>1,'message'=>'验证成功'];
}
$res=demo1();
echo $res['status']?$res['message']:'验证失败!';// 验证成功!
4.2 返回一个对象functionuser():object
{
returnnewclass(){
public$name='admin';
public$email='admin@';
};
}
$user=user();
printf("name = %s,email = %s",$user->name,$user->email);// name = admin,email = admin@
4.3 序列化字符串
4.3.1 php内置的序列化函数
如果有一些数据需要进行网络传输或保存到文件或数据表中的时候要用到序列化函数。如果这个序列化的数据只在php程序中使用,应该使用php内置的方法就可以了。
functionresult():string
{
returnserialize(['status'=>1,'message'=>'验证成功']);
}
echo result();// a:2:{s:6:"status";i:1;s:7:"message";s:12:"验证成功";}
在php中使用时要还原成原来的类型,也就说反序列化:
$arr=unserialize($str);
print_r($arr);// Array ( [status] => 1 [message] => 验证成功 )
4.3.2 JSON格式字符串
将数据转为通用的JSON格式字符串,这样的话就可以与其他语言进行数据交换了,例如:JS,JAVA…
functiondemo4():string
{
// JSON_UNESCAPED_UNICODE 显示中文,否则显示的是编码过的中文字符
// \u9a8c\u8bc1\u6210\u529f
returnjson_encode(['status'=>1,'message'=>'验证成功'],JSON_UNESCAPED_UNICODE);
}
$str=demo4();
echo $str;// {"status":1,"message":"验证成功"}
如果当前脚本接收到一个前端或其它接口发送过来的json格式的数据,可以使用json_decode进行解析。解析的目的是将外部的json还原成php能够处理的数据类型。
$res=json_decode($str);
// 默认将外部的JSON解析成Object类型。
var_dump($res);
printf('status = %d, message = %s
',$res->status,$res->message);
结果:
如果不用对象的方式访问,也可以给json_decode()函数传入第二个参数:true。
$res=json_decode($str,true);
printf('status = %d, message = %s
',$res['status'],$res['message']);
结果:
五、函数的作用域在JS中作用域有三种:全局、函数、块作用域,而在PHP中,只有全局和函数一种作用域。
全局变量也称为外部变量,是定义在函数外部的。它的作用域从变量定义处开始。
$name='残破的蛋蛋';// 声明一个$name的全局变量
$email='826350863@';// 声明一个$email的全局变量
// 声明一个user函数
functionuser(){
echo"我的名字是:${name},邮箱是:${email}";
}
// 调用函数
user();
结果:
以上结果我们发现报错了,这是因为在上面的代码中,在函数user()外面声明了两个全局变量$name和$email,但是在PHP中,不能直接在函数中使用全局变量,所以在user()函数中使用的变量$name和$email相当于新声明的两个变量,并且没有被赋值,是两个空值,所以会报错。
在函数中如果要使用全局变量可以使用global关键字或者$GLOBALS关键字。如下所示:
functionuser1(){
// 在函数内部使用global关键字引入全局变量,多个变量之间用逗号隔开
global$name,$email;
echo"我的名字是:${name},邮箱是:${email}";
}
user1();// 我的名字是:残破的蛋蛋,邮箱是:826350863@
functionuser2(){
// 在函数内部使用global关键字引入全局变量,多个变量之间用逗号隔开
echo"我的名字是:{$GLOBALS['name']},邮箱是:{$GLOBALS['email']}";
}
user2();
以上两个函数user1()和user2()都可以正常的输出结果:我的名字是:残破的蛋蛋,邮箱是:826350863@。
在$GLOBALS数组中,每一个变量都是一个元素,变量名就是它的键名,变量值就是对应的键值。$GLOBALS是一个超全局变量。
六、闭包匿名函数就是闭包(官方手册写的),闭包可以访问函数外部的自由变量/父级作用域的变量。
$demo2=function()use($name,$email){
returnsprintf('name = %s
email = %s',$name,$email);
};
echo $demo2();
结果
闭包支持引用传参:参数前加&,示例如下:
echo"当前name的值是:${name}
";
$demo3=function($myName)use(&$name){
// 闭包中将引用参数更新后,会实时映射到外部的原始参数中
$name=$myName;
echo"现在name的值是:${name}
";
};
echo $demo3('拤碎的蛋蛋');
// 输出:
// 当前name的值是:残破的蛋蛋
// 现在name的值是:拤碎的蛋蛋
结果
闭包use禁止使用以下三种参数:
超全局不让用$_GET
$this
与当前参数重名不让用
闭包经常用作函数的返回值,示例如下:
// 闭包经常用作函数的返回值
functiondemo4($site){
returnfunction($color)use($site){
returnsprintf('
%s
',$color,$site);};
}
第一种调用方式:
var_dump(demo4('PHP中文网'));
$closure=demo4('PHP中文网');
echo $closure('red');
第二种调用方式:
// 通过高阶函数调用:柯里化
echo demo4('PHP中文网')('red');
结果:
七、回调函数
回调函数是指调用函数时传递的不是一个标准的变量,而是将另外一个函数作为参数传递到调用的函数中。
call_user_func_array()调用回调函数,并把一个数组作为回调函数的参数。
语法:
call_user_func_array(callable $callback,array $param_arr):mixed
案例
classPerson{
// 实例方法
publicfunctiongetName(string$name):string
{
return"My name is ${name},";
}
publicstaticfunctionage(int$age):string
{
return"年龄是:${age}岁。";
}
}
// 调用实例方法
// 注意,这里必须是要实例化的,除非是static
$str=call_user_func_array(['Person','getName'],['残破的蛋蛋']);
// 调用静态方法
$str.=call_user_func_array(['Person','age'],[18]);
// 下面的用法跟上面相同
// $str .= call_user_func_array('Person::age', [18]);
echo $str;// My name is 残破的蛋蛋,年龄是:18岁。
八、静态变量
通常函数中的变量随着函数的调用结束就会自动销毁了,通过下面的案例我们可以得出这个结论:
functiondemo1(){
$i=1;
echo"$i
";
$i++;
}
demo1();// 1
demo1();// 1
demo1();// 1
demo1();// 1
以上代码,无论调用多少次demo1()函数结果都是输出1,说明在第2、3、4次调用函数中并没有执行到$i++,每次函数调用都是从$i = 1开始的。
如果我们想要让结果保留到下次调用,那么就需要使用到静态变量了,示例如下:
functiondemo2(){
static$i=1;
echo"$i
";
$i++;
}
demo2();// 1
demo2();// 2
demo2();// 3
demo2();// 4
以上结果分别输出了1、2、3、4,说明函数中的静态变量不会随函数调用结束而消失,而是进入到了下一次的函数调用中,这种场景可以应用在函数的多次调用中的数据共享/数据通信。