PHP 函数

预计阅读时间4 分钟 124 views

函数是 PHP 编程中的重要组成部分,通过函数可以更好地组织代码,提高代码的质量和效率。

用户自定义函数

在PHP中,可以通过特定的语法来创建自己的函数。以下是一个简单的函数定义示例:

function 示例函数($参数1, $参数2, /* ..., */ $参数n) {
    echo "这是一个示例函数。\n";
    return $返回值;
}

在函数体内,可以放置任何有效的PHP代码,甚至是其他的函数或类定义。

函数命名规则

函数名应遵循PHP标识符的一般命名规则:以字母或下划线开头,并且可以包含字母、数字和下划线。这可以通过正则表达式^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$来表示。

命名建议

建议参考用户空间命名指南来选择合适的函数名称。

函数定义时机

通常,函数不必在调用之前定义。但是,如果函数是在条件语句中定义的,则必须确保在调用之前已经定义了该函数。例如:

$创建函数 = true;

// 不能在这里调用示例函数,因为它还未定义
通用函数();

if ($创建函数) {
    function 示例函数() {
        echo "直到程序执行到这里,我才存在。\n";
    }
}

// 如果$创建函数为true,则可以安全调用示例函数
if ($创建函数) 示例函数();

function 通用函数() {
    echo "我在程序启动时就存在。\n";
}

函数中的函数

可以在一个函数内部定义另一个函数,但这个内部函数只有在外部函数被调用时才存在。例如:

function 外部函数() {
    function 内部函数() {
        echo "我只在外部函数被调用时才存在。\n";
    }
}

// 直到外部函数被调用之前,无法调用内部函数
外部函数();

// 此时可以调用内部函数,因为外部函数已经被执行过
内部函数();

作用域

PHP中的函数和类具有全局作用域,可以在一个函数内部定义而在外部调用,反之亦然。

函数重载与取消定义

PHP不支持函数重载(即不允许存在同名但参数不同的多个函数),也无法取消定义或重新定义一个已经声明的函数。

参数处理

PHP支持可变数量的参数和默认参数。可以使用func_num_args()func_get_arg()func_get_args()等内置函数来处理传递给函数的参数。

递归函数

递归函数是指函数可以直接或间接地调用自身。虽然PHP支持递归函数,但应避免递归调用层数过多(超过100-200层),以防栈溢出导致脚本终止。无限递归被视为编程错误。例如:

function 递归($a) {
    if ($a < 20) {
        echo "$a\n";
        递归($a + 1);
    }
}

函数的参数

可以通过参数列表来给函数传递数据。这些参数就像是函数的一系列输入,它们之间用逗号隔开。当函数被调用时,如果参数是值参数的话,它们会按照从左到右的顺序进行计算(也就是立即求值)。

在 PHP 中,传递参数有以下几种方式:

  • 按值传递参数(默认方式)
  • 按引用传递参数
  • 使用带有默认值的参数
  • 还支持可变数量的参数列表和命名参数

以下例子,展示如何向函数传递一个数组:

function processArray($array) {
    echo $array[0] . " + " . $array[1] . " = " . ($array[0] + $array[1]);
}

从 PHP 8.0.0 版本开始,在定义函数时可以在参数列表的最后添加一个额外的逗号,这个逗号会被忽略。这个特性对于长参数列表或具有长名称的变量尤其有用,因为它允许你将参数垂直排列,提高代码的可读性。

以下例子,展示了如何利用尾部逗号来定义一个接受多个参数的函数:

function processMultipleArgs(
    $firstParam,
    $secondParam,
    $veryLongParameterName,
    $paramWithDefault = 5,
    $anotherParam = 'default string',
) {
    // 函数体
}

注意,在 PHP 8.0.0 之前,在参数列表的末尾添加逗号是不被允许的。

通过引用传递参数

PHP 中,默认情况下,当你把一个变量传递给函数时,实际上是传递了该变量的一个副本。意味着你在函数内部改变了这个参数的值,原始变量的值不会受到影响。如果你想让函数能够直接修改传递给它的变量,那么你需要通过“引用”来传递这个变量。

要通过引用传递一个参数,你可以在函数定义中的参数前加上 & 符号。这样,函数内部对这个参数的任何修改都会反映到原始变量上。

以下例子,演示了如何通过引用传递参数:

function appendExtra(&$text) {
    $text .= 'and something extra.';
}

$myText = 'This is a string, ';
appendExtra($myText);
echo $myText;    // 输出 'This is a string, and something extra.'

默认参数的值

在 PHP 中,你可以为函数参数设置默认值。如果在函数调用时没有提供某个参数,就会使用这个默认值。但是,如果传递了 null,则不会使用默认值。

示例

function makeCoffee($type = "cappuccino") {
    return "Making a cup of $type.\n";
}

echo makeCoffee();          // 输出: Making a cup of cappuccino.
echo makeCoffee(null);      // 输出: Making a cup of .
echo makeCoffee("espresso"); // 输出: Making a cup of espresso.

默认参数可以是标量值、数组、null,以及从 PHP 8.1.0 开始还可以是使用 new ClassName() 语法创建的对象。

非标量类型的默认参数

function makeCoffee($types = ["cappuccino"], $coffeeMaker = null) {
    $device = is_null($coffeeMaker) ? "hands" : $coffeeMaker;
    return "Making a cup of " . implode(", ", $types) . " with $device.\n";
}

echo makeCoffee();                  // 输出: Making a cup of cappuccino with hands.
echo makeCoffee(["cappuccino", "lavazza"], "teapot"); // 输出: Making a cup of cappuccino, lavazza with teapot.

对象作为默认值

从 PHP 8.1.0 开始,你可以使用对象作为默认参数值。

class DefaultCoffeeMaker {
    public function brew() {
        return "Making coffee.\n";
    }
}

class FancyCoffeeMaker {
    public function brew() {
        return "Crafting a beautiful coffee just for you.\n";
    }
}

function makeCoffee($coffeeMaker = new DefaultCoffeeMaker()) {
    return $coffeeMaker->brew();
}

echo makeCoffee();                      // 输出: Making coffee.
echo makeCoffee(new FancyCoffeeMaker()); // 输出: Crafting a beautiful coffee just for you.

参数顺序

所有可选参数必须放在强制参数之后。否则,如果省略了中间的可选参数,会导致错误。

错误的参数顺序

function makeYogurt($container = "bowl", $flavour) {
    return "Making a $container of $flavour yogurt.\n";
}

echo makeYogurt("raspberry"); // 这里会引发错误

正确的参数顺序

function makeYogurt($flavour, $container = "bowl") {
    return "Making a $container of $flavour yogurt.\n";
}

echo makeYogurt("raspberry"); // 输出: Making a bowl of raspberry yogurt.

命名参数

自 PHP 8.0.0 起,你可以使用命名参数来跳过中间的可选参数。

function makeYogurt($container = "bowl", $flavour = "raspberry", $style = "Greek") {
    return "Making a $container of $flavour $style yogurt.\n";
}

echo makeYogurt(style: "natural"); // 输出: Making a bowl of raspberry natural yogurt.

可变数量的参数列表

PHP 允许你在自定义函数中接收可变数量的参数。通过在参数列表中使用 ... 语法来实现。

当你在函数参数中使用 ... 时,所有传递给该参数的值将被收集到一个数组中。

示例

function sum(...$numbers) {
    $total = 0;
    foreach ($numbers as $number) {
        $total += $number;
    }
    return $total;
}

echo sum(1, 2, 3, 4); // 输出: 10

命名参数

从 PHP 8.0.0 开始,PHP 引入了命名参数作为位置参数的扩展。命名参数允许你根据参数名而不是参数位置来传递参数。这使得参数的含义更加明确,并且可以跳过那些有默认值的参数。

语法

命名参数通过在参数名前加上冒号 : 来传递。这样可以让你在调用函数时明确指定每个参数的含义,并且不需要按照严格的顺序传递参数。

示例

function myFunction($paramName, $anotherParam = "default") {
    echo "paramName: $paramName, anotherParam: $anotherParam\n";
}

// 位置参数调用
myFunction("value1", "value2"); // 输出: paramName: value1, anotherParam: value2

// 命名参数调用
myFunction(anotherParam: "value2", paramName: "value1"); // 输出: paramName: value1, anotherParam: value2

// 跳过有默认值的参数
myFunction(paramName: "value1"); // 输出: paramName: value1, anotherParam: default

注意事项

  • 参数名必须是一个有效的标识符,不能动态指定。
  • 可以使用保留关键字作为参数名。
  • 如果有默认值的参数在中间,则可以在调用时跳过它们。

返回值

在 PHP 中,函数可以通过 return 语句返回任意类型的值,包括数组和对象。return 语句会立即终止函数的执行,并将控制权交回调用该函数的代码行。

注意

  • 如果省略了 return 语句,则函数默认返回 null
  • 函数不能直接返回多个独立的值,但可以通过返回一个数组或对象来达到类似的效果。

示例

function square($num) {
    return $num * $num;
}

echo square(4); // 输出 '16'

在这个例子中:

  • square 函数接收一个参数 $num,并返回它的平方。
  • 调用 square(4) 会返回 16,并输出结果。

返回多个值

虽然函数不能直接返回多个独立的值,但你可以通过返回一个数组来实现类似的效果:

function getCoordinates() {
    return [40.7128, -74.0060]; // 纬度和经度
}

list($latitude, $longitude) = getCoordinates();
echo "Latitude: $latitude, Longitude: $longitude"; // 输出 'Latitude: 40.7128, Longitude: -74.006'

可变函数

在 PHP 中,可变函数是指通过变量名来调用函数的能力。你可以将一个函数名存储在一个变量中,并通过该变量来调用函数。

可变函数可以用于多种场景,特别是当需要动态决定调用哪个函数时。常见的用途包括:

  1. 回调函数:在处理事件驱动编程或需要异步操作时,可以将函数名作为参数传递给另一个函数。
  2. 函数表:可以创建一个函数列表或字典,根据条件选择不同的函数来执行。
  3. 插件系统:在构建插件系统时,可以根据插件提供的函数名动态调用不同的功能。

示例

function foo() {
    echo "In foo()<br />\n";
}

function bar($arg = '') {
    echo "In bar(); argument was '$arg'.<br />\n";
}

// 使用 echo 的包装函数
function echoit($string) {
    echo $string;
}

$func = 'foo';
$func();        // 调用 foo()

$func = 'bar';
$func('test');  // 调用 bar()

$func = 'echoit';
$func('test');  // 调用 echoit()

注意事项

可变函数不能用于某些语言结构,如 echoprintunset()isset()empty()includerequire 等。为了使用这些结构作为可变函数,你需要创建一个包装函数。

调用对象的方法

也可以使用可变函数的语法来调用一个对象的方法:

class MyClass {
    public function myMethod($arg) {
        echo "In myMethod(); argument was '$arg'.<br />\n";
    }
}

$object = new MyClass();
$method = 'myMethod';

$object->$method('test');  // 调用 myMethod()

内部(内置)函数

PHP 提供了许多标准的内置函数。这些函数分为两类:

  1. 核心函数:随每个 PHP 版本自带的核心函数,如字符串处理和变量操作函数。
  2. 扩展函数:需要特定的 PHP 扩展模块支持的函数。如果没有编译时启用相应的扩展,使用这些函数会导致 “未定义函数” 的致命错误。

如何查看已加载的扩展

通过调用 phpinfo()get_loaded_extensions() 来查看 PHP 已加载的扩展库。

示例

  • 要使用 imagecreatetruecolor() 函数,需要在编译 PHP 时加上 GD 图像库的支持。
  • 要使用 mysqli_connect() 函数,需要在编译 PHP 时加上 MySQLi 扩展的支持。

查看函数原型

PHP 手册中详细介绍了如何阅读和理解函数的原型。了解函数的返回值类型以及它是否直接修改传递的参数非常重要。

  • 例如,str_replace() 返回修改后的字符串。
  • usort() 直接修改传递的数组。

注意事项

  • 如果传递给函数的参数类型不匹配,函数的行为可能是不确定的。从 PHP 8.0.0 起,这种情况下会抛出 TypeError 异常。
  • 在严格模式下,传递 null 给声明为非 null 类型的参数会导致 TypeError

强制模式下的内置函数

从 PHP 8.1.0 起,传递 null 到声明为非 null 类型的内置函数参数被弃用,并且在严格模式下会发出弃用通知。

示例

var_dump(strlen(null)); // 输出 int(0),但在 PHP 8.1.0 起会发出弃用通知

var_dump(str_contains("foobar", null)); // 输出 bool(true),但在 PHP 8.1.0 起会发出弃用通知

匿名函数

匿名函数(Anonymous functions),也称为闭包函数(closures),允许我们创建一个没有名称的临时函数。匿名函数常用于回调函数中,即作为 callable 参数的值。除此之外,它们还有其他用途。

在 PHP 中,匿名函数是通过 Closure 类来实现的。

匿名函数的使用

echo preg_replace_callback('~-([a-z])~', function ($match) {
    return strtoupper($match[1]);
}, 'hello-world');
// 输出: helloWorld

我们还可以将匿名函数赋值给一个变量。PHP 会自动将这种函数表达式转换为 Closure 类的实例。把一个匿名函数赋值给变量的语法与普通变量赋值的语法相同,结尾也要加上分号。

将匿名函数赋值给变量

$greet = function($name) {
    printf("Hello %s\r\n", $name);
};

$greet('World');
$greet('PHP');

箭头函数

箭头函数是 PHP 7.4 中引入的新语法,提供了一种更简洁的方式来编写匿名函数。箭头函数和传统的匿名函数都是 Closure 类的实现。

语法

箭头函数的基本语法如下:

fn (argument_list) => expr

这里的 argument_list 是参数列表,expr 是返回的表达式。

特点

  • 简洁性:箭头函数的语法比传统匿名函数更简洁。
  • 自动捕获变量:箭头函数会自动捕获父作用域中的变量,并且默认是按值捕获。

示例

箭头函数自动捕获变量的值

$y = 1;

$fn1 = fn($x) => $x + $y;
// 相当于通过 value 使用 $y:
$fn2 = function ($x) use ($y) {
    return $x + $y;
};

var_export($fn1(3)); // 输出 4

嵌套箭头函数

$z = 2;

$outerFn = fn($x) => {
    $innerFn = fn($y) => $x + $y + $z;
    return $innerFn(3);
};

var_export($outerFn(1)); // 输出 6

First class 可调用语法

从 PHP 8.1.0 开始,引入了 First Class 可调用语法,这是一种从 callable 创建匿名函数的新方法。这种语法的优势在于它可以进行静态分析,并且可以使用可调用对象的作用域。

语法

CallableExpr(...) 语法用于从可调用对象创建 ClosureCallableExpr 接受任何可以直接调用的表达式。

示例

简单的 First Class 可调用语法

class Foo {
    public function method() {}
    public static function staticmethod() {}
    public function __invoke() {}
}

$obj = new Foo();
$classStr = 'Foo';
$methodStr = 'method';
$staticmethodStr = 'staticmethod';

// 使用 First Class 可调用语法
$f1 = strlen(...);
$f2 = $obj(...);  // 可调用对象
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);

// 传统的 callable 语法
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);

... 是语法的一部分,表示传递给闭包的参数。

分享此文档

PHP 函数

或复制链接

本页目录