Skip to content

函数定义与调用

1. 概述

函数是 PHP 中用于封装可重用代码块的重要结构。它们允许我们将代码组织成逻辑单元,提高代码的可读性、可维护性和复用性。本知识点将详细介绍 PHP 中函数的定义、调用和基本使用方法,帮助初学者掌握 PHP 的函数编程能力。

2. 基本概念

2.1 语法

函数定义

php
function 函数名(参数1, 参数2, ...) {
    // 函数体
    return 返回值; // 可选
}

函数调用

php
函数名(参数1, 参数2, ...);

2.2 语义

  • 函数定义:使用 function 关键字定义函数,指定函数名和参数列表
  • 函数调用:使用函数名和实际参数调用函数
  • 函数体:包含函数的具体实现代码
  • 返回值:使用 return 语句返回函数的结果

2.3 规范

  • 函数名应该使用有意义的名称,遵循驼峰命名法或下划线命名法
  • 函数应该有明确的职责,只做一件事情
  • 函数参数应该有清晰的类型和含义
  • 函数应该有适当的注释,说明其用途、参数和返回值

3. 原理深度解析

3.1 函数的执行机制

当调用一个函数时,PHP 会执行以下步骤:

  1. 创建一个新的局部作用域
  2. 将实际参数的值传递给形式参数
  3. 执行函数体中的代码
  4. 遇到 return 语句时,将返回值传递给调用者,并结束函数执行
  5. 销毁局部作用域中的变量
  6. 返回到函数调用的位置继续执行

3.2 函数的作用域

  • 全局作用域:在函数外部定义的变量,在整个脚本中都可以访问
  • 局部作用域:在函数内部定义的变量,只能在函数内部访问
  • 超全局变量:在任何作用域中都可以访问的变量,如 $_GET, $_POST, $_SESSION

4. 常见错误与踩坑点

4.1 函数定义错误

错误表现:函数定义语法错误 产生原因

  • 函数名使用了保留字
  • 函数参数语法错误
  • 函数体缺少大括号 解决方案
  • 避免使用保留字作为函数名
  • 确保参数语法正确
  • 确保函数体被大括号包围

4.2 函数调用错误

错误表现:函数调用失败 产生原因

  • 函数名拼写错误
  • 参数数量不匹配
  • 参数类型不匹配 解决方案
  • 确保函数名拼写正确
  • 确保传递正确数量的参数
  • 确保参数类型正确

4.3 作用域错误

错误表现:变量未定义或访问错误 产生原因

  • 在函数内部访问未声明的全局变量
  • 在函数外部访问函数内部的局部变量 解决方案
  • 使用 global 关键字或 $GLOBALS 数组访问全局变量
  • 了解并正确使用变量作用域

5. 常见应用场景

5.1 基本函数定义与调用

场景描述:定义一个简单的函数并调用它 使用方法:使用 function 关键字定义函数,然后使用函数名调用 示例代码

php
<?php
// 定义函数
function sayHello() {
    echo "Hello, World!";
}

// 调用函数
sayHello();
?>

5.2 带参数的函数

场景描述:定义一个带参数的函数 使用方法:在函数定义时指定参数列表,调用时传递实际参数 示例代码

php
<?php
// 定义带参数的函数
function greet($name) {
    echo "Hello, " . $name . "!";
}

// 调用函数
greet("张三");
?>

5.3 带返回值的函数

场景描述:定义一个带返回值的函数 使用方法:使用 return 语句返回值,调用时接收返回值 示例代码

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

// 调用函数并接收返回值
$result = add(5, 3);
echo "5 + 3 = " . $result;
?>

5.4 带默认参数的函数

场景描述:定义一个带默认参数的函数 使用方法:在函数定义时为参数指定默认值 示例代码

php
<?php
// 定义带默认参数的函数
function greet($name = "Guest") {
    echo "Hello, " . $name . "!";
}

// 调用函数(使用默认参数)
greet();

// 调用函数(传递参数)
greet("张三");
?>

5.5 递归函数

场景描述:定义一个递归函数 使用方法:在函数内部调用自身 示例代码

php
<?php
// 定义递归函数(计算阶乘)
function factorial($n) {
    if ($n <= 1) {
        return 1;
    }
    return $n * factorial($n - 1);
}

// 调用函数
echo "5! = " . factorial(5);
?>

6. 企业级进阶应用场景

6.1 工具函数库

场景描述:创建一个工具函数库 使用方法:定义多个相关的函数,组织成一个函数库 示例代码

php
<?php
// 工具函数库

/**
 * 格式化日期
 * @param string $date 日期字符串
 * @param string $format 格式
 * @return string 格式化后的日期
 */
function formatDate($date, $format = "Y-m-d H:i:s") {
    return date($format, strtotime($date));
}

/**
 * 生成随机字符串
 * @param int $length 字符串长度
 * @return string 随机字符串
 */
function generateRandomString($length = 10) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;
}

/**
 * 验证电子邮件格式
 * @param string $email 电子邮件地址
 * @return bool 是否有效
 */
function isValidEmail($email) {
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

// 测试
echo "格式化日期:" . formatDate("2023-01-01") . PHP_EOL;
echo "随机字符串:" . generateRandomString() . PHP_EOL;
echo "电子邮件验证:" . (isValidEmail("zhangsan@example.com") ? "有效" : "无效") . PHP_EOL;
?>

6.2 业务逻辑函数

场景描述:创建处理业务逻辑的函数 使用方法:将业务逻辑封装到函数中 示例代码

php
<?php
// 业务逻辑函数

/**
 * 计算订单总价
 * @param array $items 订单 items
 * @return float 总价
 */
function calculateOrderTotal($items) {
    $total = 0;
    foreach ($items as $item) {
        $total += $item['price'] * $item['quantity'];
    }
    return $total;
}

/**
 * 应用折扣
 * @param float $total 原价
 * @param float $discount 折扣(0-1之间)
 * @return float 折扣后价格
 */
function applyDiscount($total, $discount) {
    if ($discount < 0 || $discount > 1) {
        return $total;
    }
    return $total * (1 - $discount);
}

// 测试
$orderItems = [
    ['name' => '商品1', 'price' => 100, 'quantity' => 2],
    ['name' => '商品2', 'price' => 50, 'quantity' => 1],
    ['name' => '商品3', 'price' => 200, 'quantity' => 1]
];

$subtotal = calculateOrderTotal($orderItems);
$discount = 0.1; // 10% 折扣
$total = applyDiscount($subtotal, $discount);

echo "商品总价:" . $subtotal . PHP_EOL;
echo "折扣:" . ($discount * 100) . "%" . PHP_EOL;
echo "最终价格:" . $total . PHP_EOL;
?>

7. 行业最佳实践

7.1 函数设计

实践内容

  • 函数应该有明确的职责,只做一件事情
  • 函数名应该清晰表达其功能
  • 函数参数应该有合理的默认值
  • 函数应该返回有意义的值 推荐理由:提高代码的可读性和可维护性

7.2 代码风格

实践内容

  • 使用一致的命名约定
  • 为函数添加适当的注释
  • 保持函数体简洁,避免过长的函数
  • 使用适当的缩进和空格 推荐理由:提高代码的可读性和可维护性

7.3 性能考虑

实践内容

  • 避免在函数中进行不必要的计算
  • 合理使用缓存减少重复计算
  • 避免深层递归导致的栈溢出
  • 考虑函数调用的开销 推荐理由:提高代码的执行效率

8. 常见问题答疑(FAQ)

8.1 函数名有什么命名规则?

问题描述:函数名的命名规则 回答内容

  • 函数名必须以字母或下划线开头
  • 函数名可以包含字母、数字和下划线
  • 函数名不区分大小写,但推荐使用小写字母
  • 函数名应该使用有意义的名称,遵循驼峰命名法或下划线命名法 示例代码
php
<?php
// 正确的函数名
function calculateTotal() {}
function get_user_name() {}

// 错误的函数名
// function 123function() {} // 不能以数字开头
// function function-name() {} // 不能包含连字符
?>

8.2 函数可以返回多个值吗?

问题描述:函数是否可以返回多个值 回答内容:函数只能返回一个值,但可以通过数组或对象返回多个值 示例代码

php
<?php
// 返回多个值(使用数组)
function getPerson() {
    return [
        'name' => '张三',
        'age' => 25,
        'email' => 'zhangsan@example.com'
    ];
}

// 调用函数
$person = getPerson();
echo "姓名:" . $person['name'] . PHP_EOL;
echo "年龄:" . $person['age'] . PHP_EOL;
echo "邮箱:" . $person['email'] . PHP_EOL;
?>

8.3 如何在函数内部访问全局变量?

问题描述:如何在函数内部访问函数外部定义的变量 回答内容:使用 global 关键字或 $GLOBALS 数组 示例代码

php
<?php
// 全局变量
$globalVar = "全局变量";

// 使用 global 关键字
function test1() {
    global $globalVar;
    echo $globalVar;
}

// 使用 $GLOBALS 数组
function test2() {
    echo $GLOBALS['globalVar'];
}

// 调用函数
test1();
test2();
?>

8.4 什么是递归函数?

问题描述:递归函数的定义和使用 回答内容:递归函数是在函数内部调用自身的函数,通常用于解决可以分解为相同子问题的问题 示例代码

php
<?php
// 递归函数(计算斐波那契数列)
function fibonacci($n) {
    if ($n <= 1) {
        return $n;
    }
    return fibonacci($n - 1) + fibonacci($n - 2);
}

// 调用函数
for ($i = 0; $i < 10; $i++) {
    echo fibonacci($i) . " ";
}
?>

8.5 如何定义带默认参数的函数?

问题描述:如何为函数参数设置默认值 回答内容:在函数定义时为参数指定默认值 示例代码

php
<?php
// 带默认参数的函数
function greet($name = "Guest", $message = "Hello") {
    echo $message . ", " . $name . "!";
}

// 调用函数(使用默认参数)
greet();

// 调用函数(传递部分参数)
greet("张三");

// 调用函数(传递所有参数)
greet("张三", "Hi");
?>

8.6 函数的作用域是什么?

问题描述:函数的作用域规则 回答内容

  • 在函数内部定义的变量是局部变量,只在函数内部有效
  • 在函数外部定义的变量是全局变量,在整个脚本中有效
  • 函数内部可以通过 global 关键字或 $GLOBALS 数组访问全局变量
  • 超全局变量在任何作用域中都可以访问 示例代码
php
<?php
// 全局变量
$globalVar = "全局变量";

function test() {
    // 局部变量
    $localVar = "局部变量";
    echo $localVar . PHP_EOL;
    
    // 访问全局变量
    global $globalVar;
    echo $globalVar . PHP_EOL;
}

test();
// 访问全局变量
echo $globalVar . PHP_EOL;
// 访问局部变量(会产生错误)
// echo $localVar . PHP_EOL;
?>

9. 实战练习

9.1 基础练习

题目:创建一个函数,计算两个数的和 解题思路:定义一个带两个参数的函数,返回它们的和 常见误区:函数参数错误,返回值错误 分步提示

  1. 创建一个名为 practice1.php 的文件
  2. 定义一个函数,接收两个参数
  3. 计算两个参数的和并返回
  4. 调用函数并输出结果
  5. 运行文件查看结果 参考代码
php
<?php
// 计算两个数的和
function add($a, $b) {
    return $a + $b;
}

// 测试
echo "5 + 3 = " . add(5, 3) . PHP_EOL;
echo "10 + 20 = " . add(10, 20) . PHP_EOL;
echo "-5 + 7 = " . add(-5, 7) . PHP_EOL;
?>

9.2 进阶练习

题目:创建一个函数,检查一个数是否为质数 解题思路:定义一个函数,判断一个数是否为质数 常见误区:逻辑错误,边界情况处理不当 分步提示

  1. 创建一个名为 practice2.php 的文件
  2. 定义一个函数,接收一个整数参数
  3. 实现质数判断逻辑
  4. 返回布尔值表示是否为质数
  5. 测试函数
  6. 运行文件查看结果 参考代码
php
<?php
// 检查一个数是否为质数
function isPrime($number) {
    // 处理边界情况
    if ($number <= 1) {
        return false;
    }
    
    // 检查从 2 到 sqrt($number) 的数
    for ($i = 2; $i <= sqrt($number); $i++) {
        if ($number % $i === 0) {
            return false;
        }
    }
    
    return true;
}

// 测试
$testNumbers = [2, 3, 4, 5, 10, 13, 17, 19, 20];
foreach ($testNumbers as $number) {
    if (isPrime($number)) {
        echo "{$number} 是质数" . PHP_EOL;
    } else {
        echo "{$number} 不是质数" . PHP_EOL;
    }
}
?>

9.3 挑战练习

题目:创建一个函数,实现简单的计算器 解题思路:定义一个函数,根据运算符执行相应的计算 常见误区:运算符处理错误,除数为零错误 分步提示

  1. 创建一个名为 practice3.php 的文件
  2. 定义一个函数,接收两个操作数和一个运算符
  3. 根据运算符执行相应的计算
  4. 处理错误情况(如除数为零)
  5. 返回计算结果
  6. 测试函数
  7. 运行文件查看结果 参考代码
php
<?php
// 简单计算器
function calculate($a, $b, $operator) {
    switch ($operator) {
        case '+':
            return $a + $b;
        case '-':
            return $a - $b;
        case '*':
            return $a * $b;
        case '/':
            if ($b === 0) {
                return "错误:除数不能为零";
            }
            return $a / $b;
        case '%':
            if ($b === 0) {
                return "错误:除数不能为零";
            }
            return $a % $b;
        default:
            return "错误:不支持的运算符";
    }
}

// 测试
$testCases = [
    [5, 3, '+'],
    [5, 3, '-'],
    [5, 3, '*'],
    [5, 3, '/'],
    [5, 0, '/'],
    [5, 3, '%'],
    [5, 0, '%'],
    [5, 3, '^']
];

foreach ($testCases as $case) {
    list($a, $b, $operator) = $case;
    $result = calculate($a, $b, $operator);
    echo "{$a} {$operator} {$b} = {$result}" . PHP_EOL;
}
?>

10. 知识点总结

10.1 核心要点

  • 函数是 PHP 中用于封装可重用代码块的重要结构
  • 使用 function 关键字定义函数,指定函数名和参数列表
  • 使用函数名和实际参数调用函数
  • 使用 return 语句返回函数的结果
  • 函数有自己的局部作用域,与全局作用域隔离
  • 合理使用函数可以提高代码的可读性、可维护性和复用性

10.2 易错点回顾

  • 函数名使用了保留字或不符合命名规则
  • 参数数量或类型不匹配
  • 在函数内部访问未声明的全局变量
  • 递归函数没有终止条件导致栈溢出
  • 函数返回值处理错误

11. 拓展参考资料

11.1 官方文档链接

11.2 进阶学习路径建议

  • 学习 PHP 函数参数传递
  • 学习 PHP 函数返回值
  • 学习 PHP 内置函数
  • 学习 PHP 面向对象编程