PHP函数

函数是一段封装了特定功能的代码块,它可以接受输入参数,执行特定操作,并返回结果。在PHP中,函数是代码重用和模块化的重要工具。本教程将详细介绍PHP中函数的定义、调用、参数传递、返回值、作用域等内容。

PHP函数概述

PHP中的函数可以分为两类:内置函数和用户自定义函数。

  • 内置函数:PHP提供了大量的内置函数,如字符串处理、数组操作、日期时间处理等。
  • 用户自定义函数:开发者可以根据自己的需求定义和使用函数。

用户自定义函数

定义函数

在PHP中,使用function关键字来定义函数。函数定义的基本语法如下:

function 函数名(参数1, 参数2, ...) {
    // 函数体(执行的代码)
    return 返回值; // 可选
}

函数定义的规则:

  1. 函数名必须以字母或下划线开头,后面可以跟字母、数字或下划线
  2. 函数名不区分大小写,但为了代码可读性,通常使用小写字母或驼峰命名法
  3. 函数名不能与PHP的保留字相同

简单的函数示例

<?php
// 定义一个简单的函数,用于打印问候信息
echo "<h4>简单的函数示例</h4>";

function sayHello() {
    echo "Hello, World!<br>";
}

// 调用函数
sayHello(); // 输出: Hello, World!

// 可以多次调用同一个函数
sayHello(); // 输出: Hello, World!

// 定义一个带参数的函数
function greet($name) {
    echo "Hello, $name!<br>";
}

// 调用带参数的函数
greet("张三"); // 输出: Hello, 张三!
greet("李四"); // 输出: Hello, 李四!

// 定义一个带返回值的函数
function add($a, $b) {
    return $a + $b;
}

// 调用带返回值的函数并存储结果
$result = add(3, 5);
echo "3 + 5 = $result<br>"; // 输出: 3 + 5 = 8
?>

函数参数

基本参数

函数可以接受一个或多个参数,参数在函数定义时声明,并在函数调用时传递。

<?php
// 定义一个计算矩形面积的函数
echo "<h4>基本参数示例</h4>";

function calculateArea($length, $width) {
    return $length * $width;
}

// 调用函数并传递参数
$area = calculateArea(10, 5);
echo "矩形的面积是: $area<br>"; // 输出: 矩形的面积是: 50
?>

默认参数

PHP允许为函数参数设置默认值,这样在调用函数时如果不传递该参数,就会使用默认值。

<?php
// 定义一个带默认参数的函数
echo "<h4>默认参数示例</h4>";

function welcome($name, $greeting = "Hello") {
    echo "$greeting, $name!<br>";
}

// 使用默认参数值
welcome("张三"); // 输出: Hello, 张三!

// 覆盖默认参数值
welcome("李四", "Hi"); // 输出: Hi, 李四!

// 注意:带默认值的参数必须放在参数列表的最后
function demo($required, $optional = "default") {
    echo "Required: $required, Optional: $optional<br>";
}

demo("test"); // 输出: Required: test, Optional: default
demo("test", "custom"); // 输出: Required: test, Optional: custom
?>

引用参数

默认情况下,函数参数是按值传递的,这意味着函数内部对参数的修改不会影响到外部变量。如果想要函数能够修改外部变量,可以使用引用传递参数。

<?php
// 使用引用参数修改外部变量
echo "<h4>引用参数示例</h4>";

function increment(&$value, $amount = 1) {
    $value += $amount;
}

$number = 5;
// 通过引用传递参数
increment($number);
echo "递增后的值: $number<br>"; // 输出: 递增后的值: 6

// 传递增量值
increment($number, 4);
echo "再次递增后的值: $number<br>"; // 输出: 再次递增后的值: 10
?>

可变数量的参数

PHP 5.6及以上版本支持可变数量的参数,使用三个点(...)表示。这些参数会被转换为一个数组,可以在函数内部处理。

<?php
// 使用可变数量的参数
echo "<h4>可变数量的参数示例</h4>";

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

// 传递任意数量的参数
echo "1 + 2 = " . sum(1, 2) . "<br>"; // 输出: 1 + 2 = 3
echo "1 + 2 + 3 + 4 + 5 = " . sum(1, 2, 3, 4, 5) . "<br>"; // 输出: 1 + 2 + 3 + 4 + 5 = 15

// 也可以将数组展开为参数
$values = [10, 20, 30];
echo "10 + 20 + 30 = " . sum(...$values) . "<br>"; // 输出: 10 + 20 + 30 = 60
?>

类型声明

PHP 7及以上版本支持参数类型声明,这可以提高代码的可读性和可靠性。

<?php
// 使用参数类型声明
echo "<h4>参数类型声明示例</h4>";

// 声明参数类型为int
function multiply(int $a, int $b) {
    return $a * $b;
}

echo "5 * 3 = " . multiply(5, 3) . "<br>"; // 输出: 5 * 3 = 15

// PHP会尝试自动转换类型
echo "'7' * 2 = " . multiply('7', 2) . "<br>"; // 输出: '7' * 2 = 14

// 严格类型模式(需要在文件顶部声明declare(strict_types=1);)
// 在严格类型模式下,以下调用会抛出TypeError
try {
    multiply("string", 2);
} catch (TypeError $e) {
    echo "错误: " . $e->getMessage() . "<br>";
}
?>

函数返回值

基本返回值

函数可以使用return语句返回一个值。return语句会立即结束函数执行,并将指定的值返回给调用者。

<?php
// 带返回值的函数
echo "<h4>基本返回值示例</h4>";

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

$result = square(5);
echo "5的平方是: $result<br>"; // 输出: 5的平方是: 25

// 可以返回各种类型的值
function getPerson() {
    return array(
        "name" => "张三",
        "age" => 30,
        "job" => "工程师"
    );
}

$person = getPerson();
echo "姓名: " . $person["name"] . ", 年龄: " . $person["age"] . ", 职业: " . $person["job"] . "<br>";
// 输出: 姓名: 张三, 年龄: 30, 职业: 工程师

// 不返回任何值的函数
function doSomething() {
    echo "正在做某事...<br>";
    // 没有return语句,默认返回null
}

$nothing = doSomething();
echo "返回值: " . (is_null($nothing) ? "null" : $nothing) . "<br>";
// 输出: 返回值: null
?>

返回类型声明

PHP 7及以上版本支持返回类型声明,可以指定函数返回值的类型。

<?php
// 使用返回类型声明
echo "<h4>返回类型声明示例</h4>";

function divide(int $a, int $b): float {
    return $a / $b;
}

echo "10 / 3 = " . divide(10, 3) . "<br>"; // 输出: 10 / 3 = 3.3333333333333

// 返回数组
echo "<h4>返回数组示例</h4>";

function getColors(): array {
    return ["red", "green", "blue"];
}

$colors = getColors();
echo "颜色列表: " . implode(", ", $colors) . "<br>";
// 输出: 颜色列表: red, green, blue

// 返回void类型(PHP 7.1+)
echo "<h4>返回void类型示例</h4>";

function printMessage(string $message): void {
    echo $message . "<br>";
}

printMessage("这是一个void函数"); // 输出: 这是一个void函数
?>

返回多个值

虽然函数只能返回一个值,但可以通过返回数组或对象来模拟返回多个值。

<?php
// 返回多个值(使用数组)
echo "<h4>返回多个值示例</h4>";

function calculate(int $a, int $b): array {
    $sum = $a + $b;
    $difference = $a - $b;
    $product = $a * $b;
    $quotient = $a / $b;
    
    return [$sum, $difference, $product, $quotient];
}

// 使用list()函数解构数组
list($sum, $difference, $product, $quotient) = calculate(10, 5);

echo "10 + 5 = $sum<br>";
// 输出: 10 + 5 = 15
echo "10 - 5 = $difference<br>";
// 输出: 10 - 5 = 5
echo "10 * 5 = $product<br>";
// 输出: 10 * 5 = 50
echo "10 / 5 = $quotient<br>";
// 输出: 10 / 5 = 2
?>

可变函数

可变函数允许我们通过变量来调用函数。如果变量名后有圆括号,PHP会寻找与变量值同名的函数并尝试调用它。

<?php
// 可变函数示例
echo "<h4>可变函数示例</h4>";

function sayHello() {
    echo "Hello!<br>";
}

function sayGoodbye() {
    echo "Goodbye!<br>";
}

// 使用变量调用函数
$functionName = "sayHello";
$functionName(); // 输出: Hello!

$functionName = "sayGoodbye";
$functionName(); // 输出: Goodbye!

// 可变函数与参数
function greet($name) {
    echo "Hello, $name!<br>";
}

$func = "greet";
$func("张三"); // 输出: Hello, 张三!
?>

函数作用域

作用域是指变量可访问的区域。在PHP中,有三种主要的变量作用域:

  • 局部作用域:在函数内部定义的变量,只能在函数内部访问。
  • 全局作用域:在函数外部定义的变量,只能在函数外部访问,除非使用global关键字或$GLOBALS数组。
  • 静态作用域:使用static关键字声明的变量,在函数调用之间保持其值。

局部作用域

<?php
// 局部作用域示例
echo "<h4>局部作用域示例</h4>";

function testLocalScope() {
    $localVar = "我是局部变量";
    echo $localVar . "<br>"; // 在函数内部可以访问
}

testLocalScope(); // 输出: 我是局部变量

// 在函数外部不能访问局部变量
try {
    echo $localVar . "<br>";
} catch (Exception $e) {
    echo "错误: 无法访问局部变量<br>";
}
?>

全局作用域

<?php
// 全局作用域示例
echo "<h4>全局作用域示例</h4>";

$globalVar = "我是全局变量";

echo $globalVar . "<br>"; // 在函数外部可以访问

function testGlobalScope() {
    // 方法1: 使用global关键字
    global $globalVar;
    echo "使用global关键字访问: " . $globalVar . "<br>";
    
    // 方法2: 使用$GLOBALS数组
    echo "使用$GLOBALS数组访问: " . $GLOBALS['globalVar'] . "<br>";
}

testGlobalScope();
?>

静态作用域

<?php
// 静态作用域示例
echo "<h4>静态作用域示例</h4>";

function testStaticScope() {
    static $counter = 0;
    $counter++;
    echo "计数器值: $counter<br>";
}

testStaticScope(); // 输出: 计数器值: 1
testStaticScope(); // 输出: 计数器值: 2
testStaticScope(); // 输出: 计数器值: 3
?>

递归函数

递归函数是指在函数内部调用自身的函数。递归通常用于解决可以分解为相同问题的更小实例的问题。

<?php
// 递归函数示例
echo "<h4>递归函数示例</h4>";

// 使用递归计算阶乘
function factorial($n) {
    // 基本情况: 0的阶乘是1
    if ($n <= 1) {
        return 1;
    }
    // 递归调用
    return $n * factorial($n - 1);
}

echo "5的阶乘是: " . factorial(5) . "<br>"; // 输出: 5的阶乘是: 120
echo "10的阶乘是: " . factorial(10) . "<br>"; // 输出: 10的阶乘是: 3628800

// 使用递归计算斐波那契数列
echo "<h4>递归计算斐波那契数列</h4>";

function fibonacci($n) {
    // 基本情况
    if ($n <= 0) {
        return 0;
    } elseif ($n == 1) {
        return 1;
    }
    // 递归调用
    return fibonacci($n - 1) + fibonacci($n - 2);
}

echo "前10个斐波那契数: <br>";
for ($i = 0; $i < 10; $i++) {
    echo "fibonacci($i) = " . fibonacci($i) . "<br>";
}
?>

匿名函数

匿名函数(也称为闭包)是没有名称的函数。它们可以作为变量的值,也可以作为其他函数的参数或返回值。

<?php
// 匿名函数示例
echo "<h4>匿名函数示例</h4>";

// 定义匿名函数并赋值给变量
$greet = function($name) {
    echo "Hello, $name!<br>";
};

// 调用匿名函数
$greet("张三"); // 输出: Hello, 张三!

// 匿名函数作为参数
echo "<h4>匿名函数作为参数</h4>";

function processNumbers(array $numbers, callable $operation) {
    $result = [];
    foreach ($numbers as $number) {
        $result[] = $operation($number);
    }
    return $result;
}

// 使用匿名函数计算平方
$numbers = [1, 2, 3, 4, 5];
$squaredNumbers = processNumbers($numbers, function($n) {
    return $n * $n;
});

echo "原始数组: " . implode(", ", $numbers) . "<br>";
// 输出: 原始数组: 1, 2, 3, 4, 5
echo "平方后: " . implode(", ", $squaredNumbers) . "<br>";
// 输出: 平方后: 1, 4, 9, 16, 25

// 闭包(捕获外部变量)
echo "<h4>闭包示例</h4>";

$multiplier = 2;

$multiply = function($number) use ($multiplier) {
    return $number * $multiplier;
};

echo "5 * $multiplier = " . $multiply(5) . "<br>";
// 输出: 5 * 2 = 10

// 通过引用捕获变量
$counter = 0;

$increment = function() use (&$counter) {
    $counter++;
};

$increment();
echo "计数器值: $counter<br>"; // 输出: 计数器值: 1
$increment();
echo "计数器值: $counter<br>"; // 输出: 计数器值: 2
?>

PHP函数的最佳实践

  1. 函数命名:使用有意义的函数名,通常使用动词或动词短语,清晰地表达函数的功能。
  2. 函数长度:函数应该保持简短,专注于单一任务。如果函数变得太长,考虑将其拆分为更小的、更专注的函数。
  3. 参数数量:函数的参数数量应该尽量少,一般不超过5个。如果需要传递多个相关的值,可以考虑使用数组或对象。
  4. 返回值:函数应该有明确的返回值,要么返回一个有意义的值,要么返回null或void。
  5. 类型声明:使用参数类型声明和返回类型声明,提高代码的可读性和可靠性。
  6. 错误处理:函数应该适当地处理错误情况,可以通过返回特定值、抛出异常或记录错误来实现。
  7. 文档注释:为函数添加文档注释,说明函数的目的、参数、返回值和可能抛出的异常。
  8. 避免副作用:函数应该尽量避免修改外部状态(副作用),除非这是函数的明确目的。
  9. 递归使用:谨慎使用递归,确保有明确的终止条件,避免栈溢出。对于大型数据集,考虑使用迭代替代递归。

PHP函数综合示例

<?php
// 1. 基本函数定义和调用
echo "<h4>1. 基本函数定义和调用</h4>";

// 定义一个简单的函数
function displayMessage() {
    echo "欢迎使用PHP函数示例!<br>";
}

// 调用函数
displayMessage();

// 2. 带参数和返回值的函数
echo "<h4>2. 带参数和返回值的函数</h4>";

// 计算两个数的和
function addNumbers($a, $b) {
    return $a + $b;
}

// 调用函数并显示结果
$result = addNumbers(5, 3);
echo "5 + 3 = $result<br>";

// 3. 带默认参数的函数
echo "<h4>3. 带默认参数的函数</h4>";

// 计算商品价格(带默认税率)
function calculatePrice($price, $taxRate = 0.1) {
    return $price * (1 + $taxRate);
}

// 使用默认税率
$finalPrice1 = calculatePrice(100);
echo "商品价格(默认税率10%): $finalPrice1<br>";

// 自定义税率
$finalPrice2 = calculatePrice(100, 0.15);
echo "商品价格(自定义税率15%): $finalPrice2<br>";

// 4. 引用参数
echo "<h4>4. 引用参数</h4>";

// 通过引用修改数组
function addElementToArray(&$array, $element) {
    $array[] = $element;
}

// 测试引用参数
$colors = ["红", "绿", "蓝"];
echo "原始数组: " . implode(", ", $colors) . "<br>";

// 调用函数添加元素
addElementToArray($colors, "黄");
echo "添加元素后: " . implode(", ", $colors) . "<br>";

// 5. 可变参数函数
echo "<h4>5. 可变参数函数</h4>";

// 计算多个数的平均值
function calculateAverage(...$numbers) {
    // 检查是否有参数
    if (count($numbers) === 0) {
        return 0;
    }
    
    // 计算总和
    $sum = 0;
    foreach ($numbers as $number) {
        $sum += $number;
    }
    
    // 返回平均值
    return $sum / count($numbers);
}

// 测试可变参数函数
echo "1, 2, 3, 4, 5的平均值: " . calculateAverage(1, 2, 3, 4, 5) . "<br>";
echo "10, 20, 30的平均值: " . calculateAverage(10, 20, 30) . "<br>";

// 6. 类型声明
echo "<h4>6. 类型声明</h4>";

// 带类型声明的函数
function divideNumbers(int $a, int $b): float {
    if ($b === 0) {
        throw new Exception("除数不能为零");
    }
    return $a / $b;
}

// 测试类型声明
try {
    echo "10 / 2 = " . divideNumbers(10, 2) . "<br>";
    echo "10 / 0 = " . divideNumbers(10, 0) . "<br>";
} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "<br>";
}

// 7. 递归函数
echo "<h4>7. 递归函数</h4>";

// 使用递归计算斐波那契数列
echo "斐波那契数列前12项: <br>";
for ($i = 0; $i < 12; $i++) {
    echo "fibonacci($i) = " . fibonacci($i) . "<br>";
}

// 递归函数定义(前面已经定义过)
function fibonacci($n) {
    if ($n <= 0) {
        return 0;
    } elseif ($n == 1) {
        return 1;
    }
    return fibonacci($n - 1) + fibonacci($n - 2);
}

// 8. 匿名函数和闭包
echo "<h4>8. 匿名函数和闭包</h4>";

// 匿名函数作为排序回调
$words = ["apple", "Banana", "cherry", "Date", "elderberry"];
echo "原始单词数组: " . implode(", ", $words) . "<br>";

// 不区分大小写排序
usort($words, function($a, $b) {
    return strcasecmp($a, $b);
});

echo "不区分大小写排序后: " . implode(", ", $words) . "<br>";

// 按字符串长度排序
usort($words, function($a, $b) {
    return strlen($a) - strlen($b);
});

echo "按长度排序后: " . implode(", ", $words) . "<br>";

// 9. 函数库
echo "<h4>9. 函数库</h4>";

// 数学计算函数库
echo "数学计算函数示例: <br>";
echo "abs(-10) = " . abs(-10) . "<br>";
echo "sqrt(16) = " . sqrt(16) . "<br>";
echo "pow(2, 3) = " . pow(2, 3) . "<br>";
echo "max(1, 5, 3, 9, 2) = " . max(1, 5, 3, 9, 2) . "<br>";
echo "min(1, 5, 3, 9, 2) = " . min(1, 5, 3, 9, 2) . "<br>";
echo "round(3.14159) = " . round(3.14159) . "<br>";
echo "ceil(3.1) = " . ceil(3.1) . "<br>";
echo "floor(3.9) = " . floor(3.9) . "<br>";

// 字符串处理函数
echo "<h4>字符串处理函数示例</h4>";
$text = "Hello, World!";
echo "原字符串: $text<br>";
echo "strlen(): " . strlen($text) . "<br>";
echo "strtolower(): " . strtolower($text) . "<br>";
echo "strtoupper(): " . strtoupper($text) . "<br>";
echo "ucfirst(): " . ucfirst(strtolower($text)) . "<br>";
echo "str_replace(): " . str_replace("World", "PHP", $text) . "<br>";
echo "substr(): " . substr($text, 7, 5) . "<br>";

// 数组处理函数
echo "<h4>数组处理函数示例</h4>";
$numbers = [1, 2, 3, 4, 5];
echo "原数组: " . implode(", ", $numbers) . "<br>";
echo "array_sum(): " . array_sum($numbers) . "<br>";
echo "array_product(): " . array_product($numbers) . "<br>";
echo "array_reverse(): " . implode(", ", array_reverse($numbers)) . "<br>";

// 10. 实用工具函数
echo "<h4>10. 实用工具函数</h4>";

// 格式化日期时间
function formatDateTime($timestamp = null, $format = 'Y-m-d H:i:s') {
    if ($timestamp === null) {
        $timestamp = time();
    }
    return date($format, $timestamp);
}

echo "当前日期时间: " . formatDateTime() . "<br>";
echo "当前日期: " . formatDateTime(null, 'Y-m-d') . "<br>";
echo "当前时间: " . formatDateTime(null, 'H:i:s') . "<br>";

// 生成随机字符串
function generateRandomString($length = 10, $useNumbers = true, $useSpecialChars = false) {
    $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    
    if ($useNumbers) {
        $characters .= '0123456789';
    }
    
    if ($useSpecialChars) {
        $characters .= '!@#$%^&*()_+-=[]{}|;:,.<>?';
    }
    
    $charactersLength = strlen($characters);
    $randomString = '';
    
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    
    return $randomString;
}

echo "随机字符串(10位, 仅字母): " . generateRandomString(10, false) . "<br>";
echo "随机字符串(15位, 字母+数字): " . generateRandomString(15) . "<br>";
echo "随机字符串(20位, 全部字符): " . generateRandomString(20, true, true) . "<br>";

// 验证电子邮件地址
function isValidEmail($email) {
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

$emails = ["user@example.com", "invalid-email", "another.user@domain.co.uk"];
foreach ($emails as $email) {
    echo "'$email' 是" . (isValidEmail($email) ? "" : "不") . "有效的电子邮件地址<br>";
}

// 11. 表单验证函数
echo "<h4>11. 表单验证函数</h4>";

// 处理表单提交
if (isset($_POST['submit'])) {
    $name = trim($_POST['name']);
    $email = trim($_POST['email']);
    $password = $_POST['password'];
    
    $errors = [];
    
    // 验证姓名
    if (empty($name)) {
        $errors[] = "姓名不能为空";
    } elseif (strlen($name) < 2) {
        $errors[] = "姓名至少需要2个字符";
    }
    
    // 验证电子邮件
    if (empty($email)) {
        $errors[] = "电子邮件不能为空";
    } elseif (!isValidEmail($email)) {
        $errors[] = "请输入有效的电子邮件地址";
    }
    
    // 验证密码
    if (empty($password)) {
        $errors[] = "密码不能为空";
    } elseif (strlen($password) < 6) {
        $errors[] = "密码至少需要6个字符";
    }
    
    // 显示验证结果
    if (count($errors) > 0) {
        echo "<div class='error-messages'>";
        echo "请修复以下错误:<br>";
        foreach ($errors as $error) {
            echo "- $error<br>";
        }
        echo "</div>";
    } else {
        echo "<div class='success-message'>";
        echo "表单验证成功!<br>";
        echo "姓名: " . htmlspecialchars($name) . "<br>";
        echo "电子邮件: " . htmlspecialchars($email) . "<br>";
        echo "</div>";
    }
}

// 显示表单
echo '<form method="post" action="' . htmlspecialchars($_SERVER['PHP_SELF']) . '">
    <div class="form-group">
        <label for="name">姓名:</label>
        <input type="text" id="name" name="name" value="' . (isset($_POST['name']) ? htmlspecialchars($_POST['name']) : '') . '">
    </div>
    <div class="form-group">
        <label for="email">电子邮件:</label>
        <input type="email" id="email" name="email" value="' . (isset($_POST['email']) ? htmlspecialchars($_POST['email']) : '') . '">
    </div>
    <div class="form-group">
        <label for="password">密码:</label>
        <input type="password" id="password" name="password">
    </div>
    <input type="submit" name="submit" value="提交">
</form>';

// 12. 文件操作函数
echo "<h4>12. 文件操作函数</h4>";

// 创建示例文件
$filename = "example.txt";
$content = "这是一个测试文件\n包含多行文本\n用于演示PHP文件操作函数";

// 写入文件
if (file_put_contents($filename, $content) !== false) {
    echo "文件 '$filename' 创建成功!<br>";
} else {
    echo "创建文件失败!<br>";
}

// 检查文件是否存在
if (file_exists($filename)) {
    echo "文件 '$filename' 存在。<br>";
    
    // 获取文件大小
    echo "文件大小: " . filesize($filename) . " 字节<br>";
    
    // 读取文件内容
    $fileContent = file_get_contents($filename);
    echo "文件内容: <pre>$fileContent</pre>";
    
    // 删除文件
    if (unlink($filename)) {
        echo "文件 '$filename' 已删除。<br>";
    } else {
        echo "删除文件失败!<br>";
    }
} else {
    echo "文件 '$filename' 不存在。<br>";
}
?>