函数
概述
函数是执行特定任务的可重用代码块。它们有助于组织代码、减少重复并使程序更易维护。本章介绍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";
?>下一步
现在您已经了解了函数,让我们在数组和对象中更详细地探讨数组和对象。
实践练习
- 为字符串操作创建一个工具函数库
- 使用函数构建一个计算器,实现不同的运算
- 使用高阶函数实现一个验证系统
- 创建处理数组的函数(排序、过滤、转换)
- 使用闭包构建一个简单的模板系统
函数是组织良好PHP应用程序的基础构建块!