目录
PHP 中函数的概念
函数就是将有一定功能的一些语句组织在一起的一种形式,定义函数的目的是将程序按功能分块,方便程序的使用、管理、阅读和调试。函数有两种:一种是别人写好的或系统内部提供的函数,你只要知道这个函数是干什么用的,自己会用就行了,不用管里面究竟是怎么实现的;另一种函数是自己定义的,用来实现自己独特的需求。
比如获取某天星期几,就可以封装成一个函数,之后自己想用的时候调用。
<?php
function get_week($dates){
$weekarray=array('日','一','二','三','四','五','六');
echo $dates.' 是 星期'.$weekarray[date('w',strtotime($dates))];
}
get_week('2008-08-08'); #调用函数
函数定义
function 函数名 (参数1, 参数2, ..., 参数n){
函数体;
return 返回值;
}
函数的语法格式说明如下:
- 每个函数的第一行都是函数头,由声明函数的关键字function、函数名和参数列表三部分组成,其中每一部分完成特定的功能。
- 每个自定义函数都必须使用 function 关键字声明。
- 函数名可以代表整个函数,可以将函数命名为任何名称,只要遵循变量名的命名规则即可。每个函数都有唯一的名称,但需要注意的是,在 PHP 中不能使用函数重载,所以不能定义重名的函数,也包括不能和系统函数同名。
- 声明函数时函数名后面的小括号“()”也是必须有的,在小括号中包含了一组可以接受的参数列表,参数就是声明的变量,然后在调用函数时可以将变量传递给函数。参数列表可以为空,也可以有一个或多个参数,多个参数之间使用逗号分隔。
- 函数体位于函数头后面,用花括号括起来。实际的工作是在函数体中完成的。函数被调用后,首先执行函数体中的第一条语句,执行到return语句或最外面的花括号后结束,返回到调用的程序。在函数体中可以使用任何有效的PHP代码,甚至是其他的函数或类的定义也可以在函数体中声明。
- 使用关键字 return 可以从函数中返回一个值或者表达式,程序执行到 return 语句时,该表达式将被计算,然后返回到调用函数的地方继续执行。
在声明函数时可以没有参数列表,在声明函数时也可以没有返回值。
函数的调用
不管是自定义的函数还是系统函数,如果函数不被调用,就不会执行。只要在需要使用函数的位置,使用函数名称和参数列表进行调用即可。函数被调用后开始执行函数体中的代码,执行完毕返回到调用的位置继续向下执行。
函数被调用后开始执行函数体中的代码,执行完毕返回到调用的位置继续向下执行。所以在函数调用时函数名称可以总结出以下三个作用。
- 通过函数名称可以调用函数,并让函数体的代码运行,调用几次函数体就会执行几次。
- 如果函数有参数列表,还可以通过在函数名后面的小括号中传入对应的值给参数,在函数体中使用参数来改变函数内部代码的执行行为。
- 如果函数有返回值,当函数执行完毕时就会将 return 后面的值返回到调用函数的位置,这样就可以把函数名称当做函数返回的值使用。
提示:只要声明的函数在脚本中可见,就可以通过函数名在脚本的任意位置进行调用,在 PHP 中可以在函数的声明之后调用,也可以在函数的声明之前调用,还可以在函数中调用函数。
简单示例:
<?php
function add($num1,$num2){
$a = $num1 + $num2;
return $a;
}
$sum = add(11,77); #调用
echo '$sum = '.$sum.'<br>';
函数的参数
形参、实参
参数列表是由0个、一个或多个参数组成的。每个参数是一个表达式,用逗号分隔。对于有参函数,在 PHP 脚本程序中和被调用函数之间有数据传递关系。定义函数时,函数名后面括号内的表达式称为形式参数(简称“形参”),被调用函数名后面括号中的表达式称为实际参数(简称“实参”),实参和形参需要按顺序对应传递数据。
<?php
function add($a, $b){ # $a, $b形参
echo $a.' + '.$b.' = '.($a+$b).'<br>';
}
add(11, 32); # 11,32 实参
从 PHP 8.0.0 开始,函数参数列表可以包含一个尾部的逗号,这个逗号将被忽略。
通过引用传递参数
默认情况下,函数参数通过值传递(因而即使在函数内部改变参数的值,它并不会改变函数外部的值)。如果希望允许函数修改它的参数值,必须通过引用传递参数。
<?php
function add(&$a, &$b)
{
$a = 2;
$b = 1;
}
$a = 1;
$b = 2;
add($a, $b);
var_dump($a, $b);
默认参数的值
默认值必须是常量表达式,不能是诸如变量,类成员,或者函数调用等。
<?php
function add($a = 1, $b = 1)
{
echo $a.' + '.$b.' = '.($a+$b).'<br>';
}
add();
add(2);
注意: 传引用的参数也可以有默认值。
可变数量的参数列表
PHP 在用户自定义函数中支持可变数量的参数列表。由 ...
语法实现。
注意: 还可以使用以下函数来获取可变参数 func_num_args()、 func_get_arg() 和 func_get_args(),不建议使用此方式,请使用 ... 来替代。
包含 ...
的参数,会转换为指定参数变量的一个数组,见以下示例:
<?php
function add(...$value) {
$a = 0;
foreach ($value as $n) {
$a += $n;
}
echo $a.'<br>';
}
echo add(1, 2, 3, 4, 5, 6, 7);
也可以使用 ...
语法来传递 array
<?php
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2]).'<br>';
你可以在 ...
前指定正常的位置参数。在这种情况下,只有不符合位置参数的尾部参数才会被添加到 ...
生成的数组中。
你也可以在 ...
标记前添加一个 类型声明。如果存在这种情况,那么 ...
捕获的所有参数必须是提示类的对象。
命名参数
PHP 8.0.0
开始引入了命名参数作为现有位置参数的扩展。命名参数允许根据参数名而不是参数位置向函数传参。这使得参数的含义自成体系,参数与顺序无关,并允许任意跳过默认值。
命名参数通过在参数名前加上冒号来传递。允许使用保留关键字作为参数名。参数名必须是一个标识符,不允许动态指定。
<?php
function add(a:$a, b:$b)
{
echo $a.' + '.$b.' = '.($a+$b).'<br>';
}
$a = 1;
$b = 2;
add(b:$a,a:$b);
PHP声明参数类型
在 PHP 5 中已引入函数的参数类型声明,如果给定的值不是一个合法的参数类型,那么在 PHP 5 中会出现一个 Fatal error,在 PHP 7 中则会抛出一个 TypeError exception。
在 PHP 7 中增加了参数可声明的类型种类,如表所示。
类型 | 说明 | PHP 版本 |
---|---|---|
class/interface name(类,接口) | 参数必须是指定类或接口的实例 | PHP 5.0.0 |
Array | 参数为数组类型 | PHP 5.1.0 |
Callable | 参数为有效的回调类型 | PHP 5.4.0 |
Bool | 参数为布尔型 | PHP 7.0.0 |
Float | 参数为浮点型 | PHP 7.0.0 |
Int | 参数为整型 | PHP 7.0.0 |
String | 参数为字符串 | PHP 7.0.0 |
类型转换
默认情况下,当传递的参数不是函数指定的参数类型时,PHP 会尝试将所传参数转换成指定参数类型。
严格模式
在 PHP 7 中,可以使用declare(strict_types=1)
设置严格模式,这样只有在传递的参数与函数期望得到的参数类型一致时才能正确执行,否则会抛出错误。只有一种情况例外,就是当函数期望得到的是一个浮点型数据而提供的是整型时,函数也能正常被调用。
函数的返回值
值通过使用可选的返回语句返回。可以返回包括数组和对象的任意类型。返回语句会立即中止函数的运行,并且将控制权交回调用该函数的代码行。
如果省略了 return,则返回值为
null
。
return 一次只能返回一个参数,如果要返回多个参数的话需要借助数组来完成:
<?php
function get_numbers()
{
return array (0, 1, 2);
}
list ($zero, $one, $two) = get_numbers();
从函数返回一个引用,必须在函数声明和指派返回值给一个变量时都使用引用运算符 &:
<?php
function &test() {
static $a =0; //申明一个静态变量
$a ++;
return $a ;
}
$a =&test();
echo $a.'<br>';// 1
$a = 500;
echo test().'<br>'; //501
?>
另外,在 PHP7 中增加了一个新功能——声明返回值类型。与声明参数类型相似,在非严格模式下,PHP 将会尝试将返回值类型转换为声明的类型,如果转换失败会报一个 Fatal error 错误。但在严格模式下,函数的返回值必须与声明的返回类型一致(不会尝试对返回值进行类型转换),不一致时同样会报一个 Fatal error 错误。
<?php
function add($a, $b):float{
return $a + $b;
}
var_dump(add(11, 77));
?>
严格模式:
<?php
declare(strict_types=1);
function add($a, $b):int{
return $a + $b;
}
var_dump(add(11, 77));
var_dump(add(11, 77.8)); //异常
?>
匿名函数
了解匿名函数
匿名函数(Anonymous functions)就是没有函数名的函数,也叫闭包函数(closures),是在 php5.3 中新增一个特性。最经常用作回调函数 callable参数的值。当然,也有其它应用的情况。
匿名函数目前是通过 Closure 类来实现的。
匿名函数可以作为变量的值来使用:
<?php
$a = function (){
return '匿名函数';
};
echo $a();
PHP 会自动把此种表达式转换成内置类 Closure 的对象实例。把一个 closure 对象赋值给一个变量的方式与普通变量赋值的语法是一样的,最后也要加上分号;
通常使用匿名函数当做函数或方法的回调,在很多 PHP 内置函数中都会用到匿名函数,比如 array_map 和 preg_replace_callback。
<?php
$arr = [1,2,3];
$result = array_map(function ($num) {
return $num*$num;
}, $arr);
echo '<pre>';
print_r($result);
?>
use 关键字
使用 use 关键字,闭包函数可以实现从父级作用域中继承变量,但是从 php7.1 开始,不支持继承预定义变量和 $this。
<?php
$a = 1;
$b = 2;
$test = function() use ($a) {
echo '$a = '.$a.'<br>';
echo '$b = '.($b??'没有定义').'<br>';
};
$test();
?>
需要注意的是,匿名函数虽然可以继承父级作用域中的变量,但是在匿名函数中修改变量的值不会对父级作用域中的变量造成影响,示例代码如下:
<?php
$a = 1;
$b = 2;
$test = function() use ($a) {
$a = 2;
echo '匿名函数里$a = '.$a.'<br>';
};
$test();
echo '全局$a = '.$a.'<br>';
?>
如果想要在修改匿名函数继承的变量的同时,同样修改其父级作用域中的变量,则需要在变量名的前面添加 & 符号,类似于函数中的引用传递。
自动绑定 $this
当在类的上下文中声明时,当前的类会自动与之绑定,使得 $this
在函数的作用域中可用。
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
//结果 object(Test)#1 (0) { }
?>
如果不需要当前类的自动绑定,可以使用 静态匿名函数 替代。
静态匿名函数
匿名函数允许被定义为静态化。这样可以防止当前类自动绑定到它们身上,对象在运行时也可能不会被绑定到它们上面。
<?php
class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();// 结果:报错
?>
PHP可变函数
PHP 支持可变函数的概念。这意味着如果一个变量名后有圆括号(),PHP 将寻找与变量的值同名的函数并执行它。可变函数可以用来实现包括回调函数,函数表在内的一些用途。
需要注意的是,可变函数不能直接用于例如 echo、print、unset()、isset()、empty()、include、require 以及类似的语言结构,需要使用自己包装的函数来将这些结构用作可变函数。
<?php
function a(){
echo 'a()';
}
function b(){
echo 'b()';
}
$c='a';
$c();
$c='b';
$c();
?>
可以看出同样都是在调用 $c() 函数,随着变量值的变化而调用了不同的函数。
PHP回调函数
所谓的回调函数,就是指调用函数时并不是传递一个标准的变量作为参数,而是将另一个函数作为参数传递到调用的函数中。如果在函数的格式说明中出现“callback”类型的参数,则该函数就是回调函数。
使用变量函数声明自己的回调函数:
<?php
function test($func){
for($i=1;$i<100;$i++){
if($func($i))
continue;
echo $i.'<br>';
}
}
function two($i){
return $i%2!=0;
}
function three($i){
return $i%3!=0;
}
test('two'); //100以内整除2
test('three'); //100以内整除3
?>
借助call_user_func_array()
函数自定义回调函数
函数有两个参数:第一个参数因为使用伪类型 callback,所以这个参数需要是一个字符串,表示要调用的函数名;第二个参数是一个数组类型的参数,表示参数列表,按照顺序依次传递给要调用的函数。
<?php
function test($func){
for($i=1;$i<100;$i++){
if(call_user_func_array($func,[$i]))
continue;
echo $i.'<br>';
}
}
function two($i){
return $i%2!=0;
}
function three($i){
return $i%3!=0;
}
test('two'); //100以内整除2
test('three'); //100以内整除3
?>
所有使用call_user_func_array()函数实现的自定义回调函数,或者PHP系统中为我们提供的所有回调函数,第一个参数中可以使用数组类型值,,而且数组中必须使用两个元素:
- 如果调用类中的成员方法,就需要在这个数组参数中指定第一个元素为类名称字符串,第二个元素则是该类中的静态方法名称字符串。
- 如果调用对象中的成员方法名称,则这个数组中的第一个元素为对象的引用,第二个元素则是该对象中的成员方法名称字符串。
PHP 还提供了call_user_func()
和call_user_func_array() 函数的区别是:call_user_func_array() 以数组的形式接收回调函数的参数,而 call_user_func() 则是以具体的参数来接收回调函数参数的。
<?php
function test($func, $a, $b) {
return call_user_func($func, $a, $b);
}
function add($m,$n){
return $m+$n;
}
function sub($m,$n){
return $m-$n;
}
echo test('add', 1, 2).'<br>';
echo test('sub', 2, 1).'<br>';
?>
PHP递归函数
递归函数即自调用函数,也就是函数在函数体内部直接或间接地自己调用自己。通常会在函数体中附加一个判断条件,以判断是否需要继续执行递归调用,当条件满足时会终止函数的递归调用。
<?php
function test($n) {
echo $n." ";
if($n>0)
test($n-1);
else
echo '<-->';
echo $n." ";
}
test(10);
?>
执行结果如下,分析出后半部分出现的原因。
10 9 8 7 6 5 4 3 2 1 0 <-->0 1 2 3 4 5 6 7 8 9 10
计算斐波那契数列:
1、1、2、3、5、8、13、21、34、...
实现代码如下所示:
<?php
function test($num){
//
if($num == 1 || $num == 2){
return 1;
}else{
return test($num - 1) + test($num - 2);
}
}
echo '数列第 10 位是:'.test(10);
?>
运行结果如下:
数列第 10 位是:55
内部(内置)函数
PHP 有很多标准的函数和结构。还有一些函数需要和特定地 PHP 扩展模块一起编译,否则在使用它们的时候就会得到一个致命的“未定义函数”错误。例如,要使用 image 函数中的 imagecreatetruecolor(),需要在编译 PHP 的时候加上 GD 的支持。或者,要使用 mysqli_connect()函数,就需要在编译 PHP 的时候加上 MySQLi支持。有很多核心函数已包含在每个版本的 PHP 中如字符串和变量函数。调用 phpinfo()或者 get_loaded_extensions() 可以得知 PHP 加载了那些扩展库。同时还应该注意,很多扩展库默认就是有效的。
箭头函数
箭头函数的基本语法为
fn (argument_list) => expr
-
箭头函数是 PHP 7.4 的新语法,是一种更简洁的 匿名函数写法。
-
匿名函数和箭头函数都是 Closure类的实现。
-
箭头函数支持与 匿名函数相同的功能,只是其父作用域的变量总是自动的。当表达式中使用的变量是在父作用域中定义的,它将被隐式地按值捕获。
<?php $b = 1; $fn1 = fn($a) => $a + $b; // 相当于 using $y by value: $fn2 = function ($a) use ($b) { return $a + $b; }; echo '<br>'; echo ($fn1(3)).'<br>'; echo ($fn2(3)); //函数 $fn1 和 $fn2 的行为是一样的。 ?>
-
在箭头函数嵌套的情况下同样有效。
<?php $c = 3; $fn = fn($a) => fn($b) => $a * $b * $c; echo $fn(1)(2); //运行结果 6 ?>
-
和匿名函数一样,箭头函数语法同样允许标准的函数声明,包括参数和返回类型、缺省值、变量,以及通过引用传递和返回。以下都是箭头函数的有效例子。
<?php fn($a) => $a; fn($a = 1) => $a; fn(array $a) => $a; static fn(): int => $a; fn(&$a) => $a; fn&($a) => $a; fn($a, ...$b) => $b; ?>
-
箭头函数会自动绑定上下文变量,这相当于对箭头函数内部使用的每一个变量 x 执 行 了 一 个 ‘ u s e ( x 执行了一个 `use( x执行了一个‘use(x)`。这意味着不可能修改外部作用域的任何值,若要实现对值的修改,可以使用 匿名函数来替代。
<?php $a = 1; $fn = fn() => $a++; // $a++不会影响 $a 的值 $fn(); echo $a; // 结果 1 ?>
-
可以对箭头函数使用
func_num_args()
,func_get_arg()
, 和func_get_args()
函数。