第三章 函数
函数分为系统内部函数和用户自定义函数。如果一段功能代码需要多次在不同地方使用,便可以将其封装成一个函数,即自定义函数。这样在使用时直接调用该函数即可,无需重写代码。除了自定义函数外,PHP内还提供了许多内置函数,可以直接使用。
1.函数的使用
函数可用以下语法来定义:
functin foo($arg_1, $arg_2) {
statement(函数体)
}
其中,foo表示函数名称, a r g 1 和 arg_1和 arg1和arg_2表示函数的参数。函数的命名规则:**以字母或下划线开头,后面跟字母、数字或下划线。**PHP中函数的作用域是全局的,在一个文件中定义了函数后,可以在该文件的任何地方调用。
示例:
<?php
/**
* 返回两数之和
* @param $a 参数1
* @param $b 参数2
* @return mixed
*/
function add($a, $b) {
return $a + $b;
}
$c = add(1, 2);
echo $c; // 3
?>
注意:PHP不支持函数重载,也不能取消定义或重定义已声明的函数。
2.函数的参数
PHP支持按值传递参数(默认),通过引用传递参数及默认参数,也支持可变长度参数列表。PHP支持函数参数类型声明。
2.1参数传递方式
在调用函数时,需要向函数传递参数,被传入的参数称为实参,而函数定义的参数称为形参。
PHP中函数参数传递的三种方式:按值传递、通过引用传递和默认参数。
2.1.1按值传递
按值传递的参数相当于在函数内部有这个参数的备份,即使在函数内部改变参数的值,也并不会改变函数外部的值。
- 按值传递
<?php
/**
* 值传递
* @param $a
* @return int
*/
function test($a) {
$a += 1;
return $a;
}
$a = 1;
echo test($a); // 2
echo test(2); // 3
echo $a; // 1
?>
2.1.2通过引用传递参数
如果希望允许函数修改它的参数值,就必须通过引用传递参数。这样我们在函数内部是对这个参数本身进行操作。
<?php
/**
* 引用传递
* @param $a
* @return int
*/
function test(&$a) {
$a += 1;
return $a;
}
$x = 1;
// 引用传递的参数必须是一个变量
echo test($x); // 2
echo $x; // 2
?>
2.1.3默认参数
PHP支持函数默认参数,允许使用数组array和特殊类型NULL作为默认参数。默认值必须是常量表达式,不能是变量、类成员或函数调用等。
<?php
function test($arr = array('red', 'green', 'blue'), $str = 'color') {
echo "My favourite $str is $arr[1]\n";
}
$colors = ['yellow', 'black', 'gray'];
$color = "orange";
test(); // My favourite color is green
test($colors, $color); // My favourite orange is black
?>
为避免出现意外情况,一般将默认参数放在非默认参数的右侧。
<?php
function test($arg2, $type = "arg1") {
return "$arg2 and $type.\n";
}
echo test("test"); // test and arg1.
?>
2.2参数类型声明
<?php
class A{}
class B extends A{} // 类B继承自类A
class C extends B{}
function f(A $a) {
echo get_class($a)."\n";
}
f(new A); // A
f(new B); // B
f(new C); // C
?>
<?php
function test(int $a, String $b, String $c) {
echo ($a + $b);
echo " the string is $c";
}
test( 3.14159, 2, 'hello'); // 5 the string is hello
?>
<?php
/**
* 在PHP 7中,可以使用declare(strict_types = 1)设置严格模式
*/
declare(strict_types = 1);
function test2(int $a, string $b, string $c) {
echo ($a + $b);
echo " the string is $c";
}
test2(3.84, 2, "test2");
// Fatal error: Uncaught TypeError: Argument 1 passed to test2() must be of the type int, float given
?>
2.3可变参数数量
PHP 5.6之后,参数可包含“…“来表示函数可接受一个可变数量的参数,可变参数将会被当作一个数组传递给函数。
<?php
function test(...$num) {
$acc = 0;
foreach ($num as $key => $value) {
$acc += $value;
}
return $acc;
}
echo test(1, 2, 3, 4); // 10
?>
3.函数返回值
函数的返回值可以是任意类型的数据,函数也可以不返回值。函数使用return返回数据,遇到return语句会立即终止执行。
<?php
function square($num) {
return $num * $num;
}
echo square(4); // 16
?>
函数不能返回多个值,但可以通过返回一个数组来得到类似的效果。
<?php
function square($num) {
return $num * $num;
}
echo square(4); // 16
function small_numbers() {
return array(0, 1, 2, 3);
}
list($a, $b, $c) = small_numbers();
echo $a.$b.$c; // 012
?>
在PHP 7中函数增加了返回值的类型声明,非严格模式下,PHP将会尝试将返回值类型转换成期望得到的值类型,但在严格模式下,函数的返回值类型必须与声明的返回值类型一致。
<?php
function sum($a, $b):float {
return $a + $b;
}
var_dump(sum(1, 2)); // float(3)
?>
<?php
declare(strict_types=1);
function sum($a, $b): int
{
return $a + $b;
}
var_dump(sum(1, 3.14));
// Fatal error: Uncaught TypeError: Return value of sum() must be of the type int, float returned
?>
4.可变函数
PHP支持可变函数。如果一个变量名后有圆括号,PHP将寻找与变量的值同名的函数,并尝试执行它。
<?php
function foo() {
echo "In foo() \n";
}
function bar($arg = '') {
echo "In bar(); argument was '$arg'.\n";
}
// 使用echo的包装函数
function echoit($string) {
echo $string;
}
$func = 'foo';
$func(); // In foo()
$func = 'bar';
$func('test'); // In bar(); argument was 'test'.
$func = 'echoit';
$func('test'); // test
?>
5.内置函数
6.匿名函数
匿名函数也叫闭包函数,允许临时创建一个没有指定名称的函数,通常用作回调函数参数的值。
<?php
echo preg_replace_callback('~-([a-z])~', function($match) {
return strtoupper($match[1]);
}, 'hello-world');
// helloWorld
?>
闭包函数也可以作为变量的值来使用,php会自动将这种表达式转换成内置类closure的对象实例。
<?php
$greet = function($name) {
echo "hello $name \n";
};
$greet('World');
$greet('PHP');
// hello World
// hello PHP
?>
闭包可以从父作用域继承变量,这时需要使用关键词user。
<?php
$message = 'hello';
// 没有'use'
$example = function () {
var_dump($message);
};
echo $example(); // NULL
// 继承$message
$example = function() use ($message) {
var_dump($message);
};
echo $example(); // string(5) "hello"
/**
* 当函数被定义时就继承了作用域中变量的值,而不是在调用时才继承
*/
// 此时改变$message的值对继承没有影响
$message = 'world';
echo $example(); // string(5) "hello"
// 重置$message的值为'hello'
$message = 'hello';
// 继承引用
$example = function () use (&$message) {
var_dump($message);
};
echo $example(); // string(5) "hello"
/**
* 父作用域中,$message的值被改变,当函数被调用时$message的值发生改变
*/
// 注意与非继承引用的区别
$message = 'world';
echo $example(); // string(5) "world"
// 闭包也可接收参数
$example = function ($arg) use ($message) {
var_dump($arg.' '.$message);
};
$example("hello"); // string(11) "hello world"
?>
7.递归与迭代
7.1递归
递归就是程序调用自身、函数不断引用自身,直到引用的对象已知。
构成递归需满足以下两个条件:
- 子问题需与原始问题为同样的事,且更为简单。
- 不能无限制地调用本身,必须有一个出口,化简为非递归状况处理。
例如,斐波那契数列:1,1,2,3,5,8…
<?php
function readd($n) {
if($n > 2) {
$arr[$n] = readd($n - 2) + readd($n -1); // 递归调用自身
return $arr[$n];
} else {
return 1;
}
}
echo readd(30); // 832040
?>
7.2迭代
迭代就是利用变量的原值推算出变量的一个新值。
<?php
function diedai($n) {
for($i = 0, $j = 0; $i < $n; $i++) {
$j = $j + $i;
}
return $j;
}
echo diedai(4); // 6
?>
往期文章: