Skip to content

函数

概述

函数是执行特定任务的可重用代码块。它们有助于组织代码、减少重复并使程序更易维护。本章介绍PHP中的函数定义、参数、返回值、作用域和高级函数概念。

基本函数定义

简单函数

php
<?php
// 基本函数定义
function greet() {
    echo "你好,世界!";
}

// 调用函数
greet(); // 输出:你好,世界!

// 带返回值的函数
function getMessage() {
    return "来自函数的问候!";
}

$message = getMessage();
echo $message; // 输出:来自函数的问候!

// 简单计算的函数
function addNumbers() {
    $a = 5;
    $b = 3;
    return $a + $b;
}

echo addNumbers(); // 输出:8
?>

带参数的函数

php
<?php
// 带单个参数的函数
function greetUser($name) {
    return "你好,$name!";
}

echo greetUser("Alice"); // 输出:你好,Alice!

// 带多个参数的函数
function addTwoNumbers($a, $b) {
    return $a + $b;
}

echo addTwoNumbers(5, 3); // 输出:8

// 带类型提示的函数(PHP 7+)
function multiply(int $a, int $b): int {
    return $a * $b;
}

echo multiply(4, 5); // 输出:20

// 带混合参数类型的函数
function formatMessage(string $name, int $age, bool $isActive): string {
    $status = $isActive ? "活跃" : "非活跃";
    return "用户:$name,年龄:$age,状态:$status";
}

echo formatMessage("小明", 30, true);
// 输出:用户:小明,年龄:30,状态:活跃
?>

默认参数

基本默认值

php
<?php
// 带默认参数的函数
function greetWithDefault($name = "访客") {
    return "你好,$name!";
}

echo greetWithDefault();        // 输出:你好,访客!
echo greetWithDefault("Alice"); // 输出:你好,Alice!

// 多个默认参数
function createUser($name, $role = "user", $active = true) {
    return [
        'name' => $name,
        'role' => $role,
        'active' => $active
    ];
}

$user1 = createUser("小明");
$user2 = createUser("小红", "admin");
$user3 = createUser("小强", "moderator", false);

print_r($user1); // ['name' => '小明', 'role' => 'user', 'active' => true]
print_r($user2); // ['name' => '小红', 'role' => 'admin', 'active' => true]
print_r($user3); // ['name' => '小强', 'role' => 'moderator', 'active' => false]
?>

高级默认参数

php
<?php
// 带表达式的默认参数(PHP 5.6+)
function logMessage($message, $timestamp = null, $level = "INFO") {
    if ($timestamp === null) {
        $timestamp = date('Y-m-d H:i:s');
    }
    
    return "[$timestamp] [$level] $message";
}

echo logMessage("应用程序已启动");
echo logMessage("发生错误", null, "ERROR");
echo logMessage("自定义时间", "2023-01-01 12:00:00", "DEBUG");

// 带函数调用的默认参数
function getDefaultConfig() {
    return ['theme' => 'light', 'language' => 'zh'];
}

function initializeApp($config = null) {
    if ($config === null) {
        $config = getDefaultConfig();
    }
    
    return "应用程序初始化,主题:{$config['theme']}";
}

echo initializeApp();
echo initializeApp(['theme' => 'dark', 'language' => 'en']);
?>

可变长度参数

使用 func_get_args()

php
<?php
// 可变数量参数(旧方式)
function sum() {
    $args = func_get_args();
    $total = 0;
    
    foreach ($args as $arg) {
        $total += $arg;
    }
    
    return $total;
}

echo sum(1, 2, 3);        // 输出:6
echo sum(1, 2, 3, 4, 5);  // 输出:15

// 获取特定参数
function processArgs() {
    $numArgs = func_num_args();
    echo "参数数量:$numArgs\n";
    
    for ($i = 0; $i < $numArgs; $i++) {
        $arg = func_get_arg($i);
        echo "参数 $i:$arg\n";
    }
}

processArgs("你好", 42, true);
?>

可变参数函数(PHP 5.6+)

php
<?php
// 使用 ... 运算符的可变参数函数
function sumVariadic(...$numbers) {
    $total = 0;
    foreach ($numbers as $number) {
        $total += $number;
    }
    return $total;
}

echo sumVariadic(1, 2, 3);        // 输出:6
echo sumVariadic(1, 2, 3, 4, 5);  // 输出:15

// 混合参数与可变参数
function formatList($separator, ...$items) {
    return implode($separator, $items);
}

echo formatList(", ", "apple", "banana", "orange");
// 输出:apple, banana, orange

// 带类型提示的可变参数
function calculateAverage(float ...$numbers): float {
    if (empty($numbers)) {
        return 0.0;
    }
    
    return array_sum($numbers) / count($numbers);
}

echo calculateAverage(10.5, 20.3, 15.7); // 输出:15.5

// 将数组展开为函数调用参数
$numbers = [1, 2, 3, 4, 5];
echo sumVariadic(...$numbers); // 输出:15
?>

返回值

单个返回值

php
<?php
// 不同的返回类型
function getInteger(): int {
    return 42;
}

function getString(): string {
    return "你好,世界!";
}

function getArray(): array {
    return [1, 2, 3, 4, 5];
}

function getBoolean(): bool {
    return true;
}

// 条件返回
function checkAge($age) {
    if ($age >= 18) {
        return "成年人";
    } elseif ($age >= 13) {
        return "青少年";
    } else {
        return "儿童";
    }
}

echo checkAge(25); // 输出:成年人
echo checkAge(16); // 输出:青少年
echo checkAge(10); // 输出:儿童
?>

多个返回值

php
<?php
// 返回数组实现多个值
function getNameAndAge() {
    return ["张三", 30];
}

list($name, $age) = getNameAndAge();
echo "姓名:$name,年龄:$age";

// 返回关联数组
function getUserInfo() {
    return [
        'name' => '李四',
        'email' => 'lisi@example.com',
        'age' => 25
    ];
}

$user = getUserInfo();
echo "姓名:{$user['name']},邮箱:{$user['email']}";

// 数组解构(PHP 7.1+)
['name' => $userName, 'email' => $userEmail] = getUserInfo();
echo "用户:$userName,邮箱:$userEmail";

// 返回对象
function createUser($name, $email) {
    return (object) [
        'name' => $name,
        'email' => $email,
        'created_at' => date('Y-m-d H:i:s')
    ];
}

$user = createUser("王五", "wangwu@example.com");
echo "用户:{$user->name},创建时间:{$user->created_at}";
?>

早期返回

php
<?php
// 用于验证的早期返回
function validateEmail($email) {
    if (empty($email)) {
        return false;
    }
    
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        return false;
    }
    
    return true;
}

// 保护子句
function processUser($user) {
    if (!$user) {
        return "未找到用户";
    }
    
    if (!$user['active']) {
        return "用户已停用";
    }
    
    if (!$user['verified']) {
        return "用户未验证";
    }
    
    // 主要处理逻辑
    return "用户处理成功";
}

// 多个退出点
function divide($a, $b) {
    if ($b === 0) {
        return null; // 或抛出异常
    }
    
    return $a / $b;
}

$result = divide(10, 2);
if ($result !== null) {
    echo "结果:$result";
} else {
    echo "除零错误";
}
?>

变量作用域

局部和全局作用域

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

function testScope() {
    $localVar = "我是局部变量";
    echo $localVar; // 工作正常
    
    // 没有global关键字这不会工作
    // echo $globalVar; // 未定义变量错误
    
    // 访问全局变量
    global $globalVar;
    echo $globalVar; // 现在可以工作了
}

testScope();

// 使用$GLOBALS超全局变量
function testGlobals() {
    echo $GLOBALS['globalVar']; // 访问全局变量的替代方式
}

testGlobals();

// 修改全局变量
$counter = 0;

function incrementCounter() {
    global $counter;
    $counter++;
}

incrementCounter();
incrementCounter();
echo $counter; // 输出:2
?>

静态变量

php
<?php
// 静态变量在函数调用之间保持其值
function countCalls() {
    static $count = 0;
    $count++;
    echo "函数已调用 $count\n";
}

countCalls(); // 函数已调用 1 次
countCalls(); // 函数已调用 2 次
countCalls(); // 函数已调用 3 次

// 带初始化的静态变量
function generateId() {
    static $id = 1000;
    return ++$id;
}

echo generateId(); // 1001
echo generateId(); // 1002
echo generateId(); // 1003

// 多个静态变量
function processData($data) {
    static $totalProcessed = 0;
    static $errors = 0;
    
    $totalProcessed++;
    
    if (empty($data)) {
        $errors++;
        echo "处理数据错误。总错误数:$errors\n";
        return false;
    }
    
    echo "数据已处理。总处理数:$totalProcessed\n";
    return true;
}

processData("有效数据");
processData("");
processData("更多数据");
?>

匿名函数(闭包)

基本匿名函数

php
<?php
// 匿名函数赋值给变量
$greet = function($name) {
    return "你好,$name!";
};

echo $greet("Alice"); // 输出:你好,Alice!

// 匿名函数作为回调
$numbers = [1, 2, 3, 4, 5];

$squared = array_map(function($n) {
    return $n * $n;
}, $numbers);

print_r($squared); // [1, 4, 9, 16, 25]

// 使用匿名函数过滤
$evenNumbers = array_filter($numbers, function($n) {
    return $n % 2 === 0;
});

print_r($evenNumbers); // [2, 4]
?>

使用 use 关键字的闭包

php
<?php
// 从父作用域继承变量的闭包
$multiplier = 3;

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

echo $multiply(5); // 输出:15

// use子句中的多个变量
$prefix = "结果:";
$suffix = "(已计算)";

$format = function($value) use ($prefix, $suffix) {
    return $prefix . $value . $suffix;
};

echo $format(42); // 输出:结果:42(已计算)

// 通过引用修改变量
$counter = 0;

$increment = function() use (&$counter) {
    $counter++;
    echo "计数器:$counter\n";
};

$increment(); // 计数器:1
$increment(); // 计数器:2
echo $counter; // 2(被闭包修改)
?>

箭头函数(PHP 7.4+)

php
<?php
// 箭头函数 - 简单闭包的简化语法
$numbers = [1, 2, 3, 4, 5];

// 传统匿名函数
$doubled1 = array_map(function($n) { return $n * 2; }, $numbers);

// 箭头函数(更简短)
$doubled2 = array_map(fn($n) => $n * 2, $numbers);

print_r($doubled2); // [2, 4, 6, 8, 10]

// 箭头函数自动捕获变量
$multiplier = 3;
$tripled = array_map(fn($n) => $n * $multiplier, $numbers);

print_r($tripled); // [3, 6, 9, 12, 15]

// 更复杂的箭头函数
$users = [
    ['name' => '小明', 'age' => 30],
    ['name' => '小红', 'age' => 25],
    ['name' => '小强', 'age' => 35]
];

$names = array_map(fn($user) => $user['name'], $users);
$adults = array_filter($users, fn($user) => $user['age'] >= 18);

print_r($names); // ['小明', '小红', '小强']
print_r($adults); // 所有用户(都是成年人)
?>

高阶函数

函数作为参数

php
<?php
// 接受另一个函数作为参数的函数
function processArray($array, $callback) {
    $result = [];
    foreach ($array as $item) {
        $result[] = $callback($item);
    }
    return $result;
}

// 不同的回调函数
function double($n) {
    return $n * 2;
}

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

$numbers = [1, 2, 3, 4, 5];

$doubled = processArray($numbers, 'double');
$squared = processArray($numbers, 'square');

print_r($doubled); // [2, 4, 6, 8, 10]
print_r($squared); // [1, 4, 9, 16, 25]

// 使用匿名函数
$cubed = processArray($numbers, function($n) {
    return $n * $n * $n;
});

print_r($cubed); // [1, 8, 27, 64, 125]
?>

返回函数的函数

php
<?php
// 返回另一个函数的函数
function createMultiplier($factor) {
    return function($number) use ($factor) {
        return $number * $factor;
    };
}

$double = createMultiplier(2);
$triple = createMultiplier(3);

echo $double(5); // 输出:10
echo $triple(5); // 输出:15

// 更复杂的例子:创建验证器
function createValidator($rules) {
    return function($data) use ($rules) {
        $errors = [];
        
        foreach ($rules as $field => $rule) {
            if ($rule === 'required' && empty($data[$field])) {
                $errors[] = "$field 是必填项";
            }
            
            if ($rule === 'email' && !filter_var($data[$field], FILTER_VALIDATE_EMAIL)) {
                $errors[] = "$field 必须是有效的邮箱";
            }
        }
        
        return $errors;
    };
}

$userValidator = createValidator([
    'name' => 'required',
    'email' => 'email'
]);

$errors = $userValidator(['name' => '', 'email' => 'invalid-email']);
print_r($errors); // ['name 是必填项', 'email 必须是有效的邮箱']
?>

Built-in Functions

String Functions

php
<?php
// Common string functions
$text = "Hello, World!";

echo strlen($text);           // 13 (length)
echo strtoupper($text);       // "HELLO, WORLD!"
echo strtolower($text);       // "hello, world!"
echo ucfirst($text);          // "Hello, world!"
echo ucwords($text);          // "Hello, World!"

// String manipulation
$name = "  John Doe  ";
echo trim($name);             // "John Doe" (remove whitespace)
echo ltrim($name);            // "John Doe  " (remove left whitespace)
echo rtrim($name);            // "  John Doe" (remove right whitespace)

// String searching and replacement
$sentence = "The quick brown fox jumps over the lazy dog";
echo strpos($sentence, "fox");        // 16 (position of "fox")
echo str_replace("fox", "cat", $sentence); // Replace "fox" with "cat"
echo substr($sentence, 0, 9);         // "The quick" (substring)

// String splitting and joining
$words = explode(" ", $sentence);     // Split into array
$rejoined = implode("-", $words);     // Join with hyphens
?>

Array Functions

php
<?php
$numbers = [3, 1, 4, 1, 5, 9, 2, 6];

// Array information
echo count($numbers);         // 8 (number of elements)
echo array_sum($numbers);     // 31 (sum of all elements)
echo max($numbers);           // 9 (maximum value)
echo min($numbers);           // 1 (minimum value)

// Array manipulation
sort($numbers);               // Sort in ascending order
rsort($numbers);              // Sort in descending order
shuffle($numbers);            // Randomize order

// Array searching
$position = array_search(5, $numbers);  // Find position of value 5
$exists = in_array(4, $numbers);        // Check if value exists

// Array filtering and mapping
$evens = array_filter($numbers, function($n) {
    return $n % 2 === 0;
});

$doubled = array_map(function($n) {
    return $n * 2;
}, $numbers);

// Array merging and slicing
$moreNumbers = [7, 8, 9];
$combined = array_merge($numbers, $moreNumbers);
$slice = array_slice($numbers, 2, 3);  // Get 3 elements starting at index 2
?>

Math Functions

php
<?php
// Basic math functions
echo abs(-5);           // 5 (absolute value)
echo round(3.7);        // 4 (round to nearest integer)
echo floor(3.7);        // 3 (round down)
echo ceil(3.2);         // 4 (round up)

// Power and root functions
echo pow(2, 3);         // 8 (2 to the power of 3)
echo sqrt(16);          // 4 (square root)

// Random numbers
echo rand(1, 10);       // Random integer between 1 and 10
echo mt_rand(1, 100);   // Better random number generator

// Trigonometric functions
echo sin(M_PI / 2);     // 1 (sine of 90 degrees in radians)
echo cos(0);            // 1 (cosine of 0 degrees)

// Number formatting
echo number_format(1234.567, 2);        // "1,234.57"
echo number_format(1234567, 0, '.', ','); // "1,234,567"
?>

Function Best Practices

Single Responsibility Principle

php
<?php
// Bad: Function doing too many things
function processUserBad($userData) {
    // Validate data
    if (empty($userData['email'])) {
        return false;
    }
    
    // Hash password
    $userData['password'] = password_hash($userData['password'], PASSWORD_DEFAULT);
    
    // Save to database
    // ... database code ...
    
    // Send welcome email
    // ... email code ...
    
    return true;
}

// Good: Separate functions for each responsibility
function validateUserData($userData) {
    $errors = [];
    
    if (empty($userData['email'])) {
        $errors[] = 'Email is required';
    }
    
    if (empty($userData['password'])) {
        $errors[] = 'Password is required';
    }
    
    return $errors;
}

function hashPassword($password) {
    return password_hash($password, PASSWORD_DEFAULT);
}

function saveUser($userData) {
    // Database save logic
    return true; // or user ID
}

function sendWelcomeEmail($userEmail) {
    // Email sending logic
    return true;
}

// Main function orchestrates the process
function processUser($userData) {
    $errors = validateUserData($userData);
    if (!empty($errors)) {
        return ['success' => false, 'errors' => $errors];
    }
    
    $userData['password'] = hashPassword($userData['password']);
    $userId = saveUser($userData);
    
    if ($userId) {
        sendWelcomeEmail($userData['email']);
        return ['success' => true, 'user_id' => $userId];
    }
    
    return ['success' => false, 'errors' => ['Failed to save user']];
}
?>

Input Validation and Error Handling

php
<?php
// Function with proper input validation
function calculateBMI($weight, $height) {
    // Validate input types
    if (!is_numeric($weight) || !is_numeric($height)) {
        throw new InvalidArgumentException('Weight and height must be numeric');
    }
    
    // Validate input ranges
    if ($weight <= 0) {
        throw new InvalidArgumentException('Weight must be positive');
    }
    
    if ($height <= 0) {
        throw new InvalidArgumentException('Height must be positive');
    }
    
    // Convert height to meters if it seems to be in centimeters
    if ($height > 3) {
        $height = $height / 100;
    }
    
    $bmi = $weight / ($height * $height);
    
    return round($bmi, 2);
}

// Usage with error handling
try {
    $bmi = calculateBMI(70, 1.75);
    echo "BMI: $bmi";
} catch (InvalidArgumentException $e) {
    echo "Error: " . $e->getMessage();
}

// Function with optional error handling
function safeDivide($a, $b, &$error = null) {
    if ($b === 0) {
        $error = "Division by zero";
        return null;
    }
    
    return $a / $b;
}

$error = null;
$result = safeDivide(10, 0, $error);

if ($error) {
    echo "Error: $error";
} else {
    echo "Result: $result";
}
?>

Documentation and Type Hints

php
<?php
/**
 * Calculates the distance between two geographic points
 * 
 * @param float $lat1 Latitude of first point
 * @param float $lon1 Longitude of first point
 * @param float $lat2 Latitude of second point
 * @param float $lon2 Longitude of second point
 * @param string $unit Unit of measurement ('km' or 'miles')
 * @return float Distance between points
 * @throws InvalidArgumentException If coordinates are invalid
 */
function calculateDistance(
    float $lat1, 
    float $lon1, 
    float $lat2, 
    float $lon2, 
    string $unit = 'km'
): float {
    // Validate coordinates
    if ($lat1 < -90 || $lat1 > 90 || $lat2 < -90 || $lat2 > 90) {
        throw new InvalidArgumentException('Latitude must be between -90 and 90');
    }
    
    if ($lon1 < -180 || $lon1 > 180 || $lon2 < -180 || $lon2 > 180) {
        throw new InvalidArgumentException('Longitude must be between -180 and 180');
    }
    
    // Haversine formula
    $earthRadius = ($unit === 'miles') ? 3959 : 6371;
    
    $dLat = deg2rad($lat2 - $lat1);
    $dLon = deg2rad($lon2 - $lon1);
    
    $a = sin($dLat / 2) * sin($dLat / 2) +
         cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
         sin($dLon / 2) * sin($dLon / 2);
    
    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
    
    return $earthRadius * $c;
}

// Usage
$distance = calculateDistance(40.7128, -74.0060, 34.0522, -118.2437, 'miles');
echo "Distance: " . number_format($distance, 2) . " miles";
?>

下一步

现在您已经了解了函数,让我们在数组和对象中更详细地探讨数组和对象。

实践练习

  1. 为字符串操作创建一个工具函数库
  2. 使用函数构建一个计算器,实现不同的运算
  3. 使用高阶函数实现一个验证系统
  4. 创建处理数组的函数(排序、过滤、转换)
  5. 使用闭包构建一个简单的模板系统

函数是组织良好PHP应用程序的基础构建块!

本站内容仅供学习和研究使用。