定义一个函数
function test($a, $b){
$temp = $a + $b;
return $temp;
}
在php中,任何有效的 PHP 代码都有可能出现在函数内部,甚至包括其它函数和类定义。 同时,由于PHP 中的所有函数和类都具有全局作用域,可以定义在一个函数之内而在之外调用,反之亦然。 也就是说,在函数内定义的函数或类,在函数之外可以直接使用,使用时与定义它的函数并无关联。
另外,有别于变量,函数是不能重复定义的。
有条件地定义一个函数
有条件定义一个函数包括两种情形,即函数定义在一个条件语句中,或定义在另一个函数(假设为函数a)中,这时语句是否执行以及函数a是否调用,就成了函数是否定义的条件。在这两种情况下,函数必须是确定已经定义之后,才可以调用。
除了这两种情况,函数是可以先调用再定义的。
$a = 4;
if($a % 2 == 0)
{
function test1(){
echo "test1\n";
}
}
switch($a)
{
case 4;
function test2(){
echo "test2\n";
}
break;
}
function fun()
{
function test3(){
echo "test3\n";
}
}
fun();
test1();
test2();
test3();
本示例能够正常运行,对于test1(),因为if语句确实运行过了,对于test2(),switch中的分支确实运行过了,对于test3(),fun()函数也是确实运行过了,只有这样,这些函数才得以正常运行。引用参数
通过在函数参数前添加"&"符号,可以定义引用参数,这时形参将成为实参的一个别名:
$a = 4;
function test1(&$x){
$x++;
}
test1($a);
echo $a; // 5
默认参数
可以给函数参数添加默认参数,这种情况下,如果调用时不提供实参,将会以默认参数作为实参。默认参数可以是各种标量、数组、NULL等,不过必须是常量表达式,不能是诸如变量,类成员,或者函数调用等。
$str = "Hi";
function test($a, $b=null, $c=array("Ann","Nicke","Jeck"), &$x="Hello"){
foreach($c as $name)
{
if($a-- <= 0) break;
echo "$x $name\n";
}
}
test(2);
注意:
1.提供了默认参数的参数必须全部集中在参数列表的最后
2.引用参数也可以有默认参数(尽管上例没能很好地体现这一点)
类型声明
默认情况下函数的参数是没有指定类型的,这样的参数可以传递任何类型的参数。不过也可以为参数指定一个类型,如果参数的类型不正确,将会抛出TypeError异常。另外,虽然指定了参数的类型,仍可以通过给参数设定一个null默认值,使得参数可以接收null。
function test(int $x) {
return $x * $x;
}
echo test(2); // 4
类名/接口名/array/callable/bool/float/int/string/self
注意:
1.不能使用integer/boolean/double等
2.self只用于类或接口方法,表示参数的类型与所有在类或接口类型相同
3.对于指定为类的参数,实参可以是子类对象
4.如果不开启严格模式,那么在默认情况下,PHP将会强迫错误类型的值转为函数期望的标量类型。 例如,一个函数的一个参数期望是string,但传入的是integer,最终函数得到的将会是一个string类型的值。
function test(float $x) {
return $x * $x;
}
echo test("2x"); // 4
declare(strict_types=1);
function test(float $x) {
return $x * $x;
}
echo test("2x"); // 异常
可变数量的参数列表
函数可以接受不定数量的参数,这些参数可以在函数内部以数组的形式获得。
function test(int ...$num) {
$count = 0;
foreach($num as $x)
$count += $x;
return $count;
}
echo test(1,2,3); // 6
可变数量的参数最多只能有一个,而且只能出现在参数列表的最后一个。同时,可变数量的参数也可以是引用参数,可以有或者没有类型声明。
function test($x, $y=2, &...$num) {
foreach($num as &$n) {
$n += $x;
$n *= $y;
}
}
$a = 4;
$b = 5;
test(2,3,$a,$b);
echo "$a\n"; // 18
echo "$b\n"; // 21
可变数量的参数还有第二种实现方式,即使用以下三个函数:
int func_num_args ( void ) - 实参个数
mixed func_get_arg ( int $arg_num ) - 获取指定编号的实参值
array func_get_args ( void ) - 获取全部实参,返回一个数组
这3个函数可用于任意函数内部,与是否使用...参数无关
function test1($x, $y, ...$num) {
var_dump(func_num_args());
var_dump(func_get_args());
}
function test2(){
$count = 0;
for($i=0; $i<func_num_args(); $i++)
$count += func_get_arg($i);
return $count;
}
test1(1,2,3,4);
echo test2(1,2,3,4);
--------------------int(4)
array(4) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
}
10
...运算符不仅可以用于函数形参,也可以用于函数实参,效果是将数组类型的实参拆解为多个值
function test($x, $y) {
return $x + $y;
}
$a = [1,2,3];
echo test(...$a); // 3
echo test(...[3,4]); // 7
echo test(2,3,4); // 5 实参数量可以比形参多,但不能少,否则出错
返回值
可以使用return语句从函数中返回一个值。可以返回包括数组和对象的任意类型。如果省略了 return,则返回值为 NULL。 函数不能返回多个值,但可以通过返回一个数组来得到类似的效果。
返回一个引用
要让函数返回一个引用,必须在函数声明和函数调用处,都使用&运算符,而return语句处则不需要。
function &test(&$x, &$y) {
if($x > $y) return $x;
else return $y;
}
$a = 3;
$b = 4;
$c = &test($a, $b);
$c++;
echo "$a\n"; // 3
echo "$b\n"; // 5
function &test($x) {
static $max = 0;
$max = $x > $max ? $x : $max;
return $max;
}
$a = 3;
$b = 4;
$c = &test($a);
test($b);
echo $c; // 4
在本例中,局部变量定义成静态变量,从语法上这不是必须的,但是如果定义成非静态变量,则每次函数返回的引用都将是新的局部变量(也就是每次函数调用都会临时创建的局部变量)。指定函数的返回类型
与函数的参数可以声明类型一样,函数的返回值也可以声明类型,例如:
function numAdd($x, $y) : int {
return $x + $y;
}
$x = numAdd(3,4);
$y = numAdd("23", true);
echo $x; // 7
echo $y; // 24
与参数的类型一样,如果需要严格的类型匹配,可以为文件添加 declare(strict_types=1); 声明。
可变函数
与可变变量类似,PHP 支持可变函数的概念。这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它。可变函数可以用来实现包括回调函数,函数表在内的一些用途。不过,可变函数不能用于例如 echo,print,unset(),isset(),empty(),include,require 以及类似的语言结构。如果确实需要,可自行对这些语言结构进行函数封装。
一般情况下,在调用函数或方法时,函数名前面是不会有$符号的,例如:
var_dump();
如果出现了$符号,则表明$之后的标识符不是一个函数名,只有在与$结合起来解析后,才会得到真正的函数名(或方法名)。
function myPrint($x) {
echo "$x\n";
}
function varPrint($x) {
return print $x;
}
$a = "myPrint";
$a("Hello world!");
这里便出现了$xxx()的形式,类似的,方法也可以使用可变函数:xxx->$xxx(); xxx::$xxx();
可变的变量不仅仅只能是一个字符串,还可以是数组,一般包含以下几种形式:
1.字符串:函数名或方法名
2.字符串:"类名::静态方法名"
3.数组:array("类名","静态方法名")
4.数组:array(对象,"对象方法名")
另外,注意在使用类的静态成员时,解析的优先问题:
class TestClass {
public static $a = "func";
}
function func() {
return "func";
}
echo TestClass::$a; // func
echo TestClass::$a(); // 出错
第二个输出语句被解析为:
(TestClass::($a))()
而不是:
(TestClass::$a)()
由于$a未定义,所以出错。
class TestClass {
public static $a = "func";
public static function ft() {
return "ft";
}
}
function func() {
return "func";
}
$a = "ft";
echo TestClass::$a; // func
echo TestClass::$a(); // ft
本例中,两个输出语句都能正常输出。匿名函数/闭包
匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。 目前通过 Closure 类来实现。
定义匿名函数时,不需要指定函数名,类似如下形式:
function ($a ...) {}
可以直接将这样的表达式传递给函数调用,也可以赋值给一个变量
$p = function($x) {
echo "$x\n";
};
$p("Hello world!");
闭包的特色功能在于继承父作用域的变量,只需要使用use语言结构。注意,PHP 7.1 起,不能传入此类变量: 超级全局变量、 $this 或者和参数重名。
$message = 'hello';
// 继承 $message
$example = function () use ($message) {
var_dump($message);
};
$example(); // string(5) "hello"
// 变量的值在函数定义时继承,而不是在函数调用时
$message = 'world';
$example(); // string(5) "hello"
在本例中,如果不使用use继承变量,那么函数内$message实际上只是一个未定义的局部变量。从父作用域中继承变量与使用全局变量是不同的。全局变量存在于一个全局的范围,无论当前在执行的是哪个函数。而 闭包的父作用域是定义该闭包的函数(不一定是调用它的函数)。下面是一个相对实用一些的闭包实例:
function operate($operator){
return function($a,$b) use($operator) {
switch($operator)
{
case "-":
return $a-$b;
case "+":
return $a+$b;
}
};
}
$subtraction = operate("-");
echo $subtraction(4,3); // 1
$addition = operate("+");
echo $addition(1,2); // 3
$message = 'hello';
// 引用继承
$example = function () use (&$message) {
var_dump($message);
};
$example(); // string(5) "hello"
// 外界变量的改变可以映射到闭包内部
$message = 'world';
$example(); // string(5) "world"
下面的例子演示了引用继承多个变量:
function func($x, $y) {
return function() use(&$x, &$y) {
echo $x + $y;
$x++;
$y++;
};
}
$a = func(4,5);
$a(); // 9
$a(); // 11
$a(); // 13
在类内部定义的匿名函数会自动绑定$this,如果要避免此特性,可将匿名函数定义成静态的
class MyClass{
public function __construct($num) {
$this->num = $num;
}
public function func() {
return function() {
var_dump($this->num);
};
}
}
$a = new MyClass(3);
$x = $a->func();
$x(); // int(3)
$a->num = 4;
$x(); // int(4)
class MyClass{
public function __construct($num) {
$this->num = $num;
}
public function func() {
return static function() {
};
}
}