本章目标
- 掌握函数的定义和调用
- 理解参数传递机制
- 学会使用返回值
- 了解变量作用域
- 掌握匿名函数和闭包
- 学会使用内置函数
- 理解函数的高级特性
4.1 函数基础
4.1.1 函数定义
基本语法:
<?php
// 基本函数定义
function greet() {
echo "Hello, World!";
}
// 调用函数
greet(); // 输出:Hello, World!
// 带参数的函数
function greetUser($name) {
echo "Hello, $name!";
}
greetUser("张三"); // 输出:Hello, 张三!
// 带返回值的函数
function add($a, $b) {
return $a + $b;
}
$result = add(5, 3);
echo $result; // 输出:8
// 带默认参数的函数
function greetWithTitle($name, $title = "先生") {
return "您好,{$title}{$name}!";
}
echo greetWithTitle("张三"); // 输出:您好,先生张三!
echo greetWithTitle("李四", "女士"); // 输出:您好,女士李四!
?>
4.1.2 函数命名规则
<?php
// 正确的函数名
function calculateTotal() {}
function get_user_info() {}
function isValidEmail() {}
function _privateFunction() {}
function myFunction123() {}
// 错误的函数名
// function 123function() {} // 不能以数字开头
// function my-function() {} // 不能包含连字符
// function my function() {} // 不能包含空格
// function class() {} // 不能使用关键字
// 函数名不区分大小写
function MyFunction() {
echo "大写函数";
}
myfunction(); // 可以调用
MYFUNCTION(); // 也可以调用
MyFunction(); // 还是可以调用
?>
4.1.3 函数文档注释
<?php
/**
* 计算两个数的和
*
* 这个函数接受两个数值参数,返回它们的和
*
* @param float $a 第一个数
* @param float $b 第二个数
* @return float 两数之和
* @throws InvalidArgumentException 当参数不是数值时
* @example
* $result = add(5, 3); // 返回 8
* $result = add(2.5, 1.5); // 返回 4.0
*/
function add($a, $b) {
if (!is_numeric($a) || !is_numeric($b)) {
throw new InvalidArgumentException('参数必须是数值');
}
return $a + $b;
}
/**
* 格式化用户信息
*
* @param array $user 用户信息数组
* @param string $format 格式化模板
* @return string 格式化后的字符串
* @since 1.0.0
* @author 张三 <zhangsan@example.com>
*/
function formatUserInfo(array $user, string $format = '{name} ({email})') {
return str_replace(
['{name}', '{email}', '{age}'],
[$user['name'] ?? '', $user['email'] ?? '', $user['age'] ?? ''],
$format
);
}
?>
4.2 参数传递
4.2.1 值传递
<?php
// 值传递(默认方式)
function increment($value) {
$value++;
echo "函数内部:$value\n";
}
$number = 5;
increment($number);
echo "函数外部:$number\n";
// 输出:
// 函数内部:6
// 函数外部:5
// 数组的值传递
function modifyArray($arr) {
$arr[] = 'new item';
print_r($arr);
}
$myArray = ['item1', 'item2'];
modifyArray($myArray);
print_r($myArray);
// 函数内输出:['item1', 'item2', 'new item']
// 函数外输出:['item1', 'item2']
?>
4.2.2 引用传递
<?php
// 引用传递
function incrementByReference(&$value) {
$value++;
echo "函数内部:$value\n";
}
$number = 5;
incrementByReference($number);
echo "函数外部:$number\n";
// 输出:
// 函数内部:6
// 函数外部:6
// 数组的引用传递
function modifyArrayByReference(&$arr) {
$arr[] = 'new item';
print_r($arr);
}
$myArray = ['item1', 'item2'];
modifyArrayByReference($myArray);
print_r($myArray);
// 函数内输出:['item1', 'item2', 'new item']
// 函数外输出:['item1', 'item2', 'new item']
// 交换两个变量的值
function swap(&$a, &$b) {
$temp = $a;
$a = $b;
$b = $temp;
}
$x = 10;
$y = 20;
echo "交换前:x=$x, y=$y\n";
swap($x, $y);
echo "交换后:x=$x, y=$y\n";
?>
4.2.3 默认参数
<?php
// 基本默认参数
function createUser($name, $email, $role = 'user', $active = true) {
return [
'name' => $name,
'email' => $email,
'role' => $role,
'active' => $active
];
}
$user1 = createUser('张三', 'zhangsan@example.com');
$user2 = createUser('李四', 'lisi@example.com', 'admin');
$user3 = createUser('王五', 'wangwu@example.com', 'user', false);
// 默认参数必须在必需参数之后
// function invalidFunction($name = 'default', $email) {} // 错误!
// 使用数组作为默认参数
function processData($data, $options = []) {
$defaultOptions = [
'validate' => true,
'format' => 'json',
'encoding' => 'utf-8'
];
$options = array_merge($defaultOptions, $options);
// 处理数据
return $options;
}
$result1 = processData($data);
$result2 = processData($data, ['format' => 'xml']);
// 使用null作为默认值
function connectDatabase($host = null, $port = null) {
$host = $host ?? 'localhost';
$port = $port ?? 3306;
echo "连接到 $host:$port\n";
}
connectDatabase();
connectDatabase('192.168.1.100');
connectDatabase('192.168.1.100', 3307);
?>
4.2.4 可变参数
<?php
// 使用func_get_args()获取所有参数
function sum() {
$args = func_get_args();
$total = 0;
foreach ($args as $arg) {
if (is_numeric($arg)) {
$total += $arg;
}
}
return $total;
}
echo sum(1, 2, 3, 4, 5); // 输出:15
echo sum(10, 20); // 输出:30
echo sum(1.5, 2.5, 3.5); // 输出:7.5
// 使用func_num_args()获取参数数量
function debugArgs() {
$numArgs = func_num_args();
echo "参数数量:$numArgs\n";
for ($i = 0; $i < $numArgs; $i++) {
$arg = func_get_arg($i);
echo "参数 $i: $arg\n";
}
}
debugArgs('a', 'b', 'c');
// PHP 5.6+ 使用...操作符
function sumVariadic(...$numbers) {
$total = 0;
foreach ($numbers as $number) {
$total += $number;
}
return $total;
}
echo sumVariadic(1, 2, 3, 4, 5); // 输出:15
// 混合使用固定参数和可变参数
function formatMessage($template, ...$args) {
return sprintf($template, ...$args);
}
echo formatMessage("Hello %s, you are %d years old", "张三", 25);
// 类型声明的可变参数
function sumIntegers(int ...$numbers): int {
return array_sum($numbers);
}
echo sumIntegers(1, 2, 3, 4, 5); // 输出:15
?>
4.2.5 命名参数(PHP 8+)
<?php
// PHP 8+ 命名参数
function createUser($name, $email, $role = 'user', $active = true) {
return [
'name' => $name,
'email' => $email,
'role' => $role,
'active' => $active
];
}
// 使用命名参数
$user1 = createUser(
name: '张三',
email: 'zhangsan@example.com'
);
$user2 = createUser(
email: 'lisi@example.com',
name: '李四',
active: false
);
// 混合使用位置参数和命名参数
$user3 = createUser('王五', 'wangwu@example.com', active: false);
// 在数组函数中使用命名参数
$data = ['c' => 3, 'a' => 1, 'b' => 2];
ksort(array: $data, flags: SORT_STRING);
// 在内置函数中使用命名参数
$html = htmlspecialchars(
string: '<script>alert("XSS")</script>',
flags: ENT_QUOTES,
encoding: 'UTF-8'
);
?>
4.3 返回值
4.3.1 基本返回值
<?php
// 返回不同类型的值
function getString() {
return "Hello World";
}
function getNumber() {
return 42;
}
function getArray() {
return [1, 2, 3, 4, 5];
}
function getAssociativeArray() {
return [
'name' => '张三',
'age' => 25,
'email' => 'zhangsan@example.com'
];
}
function getBoolean() {
return true;
}
// 条件返回
function divide($a, $b) {
if ($b == 0) {
return false; // 返回false表示错误
}
return $a / $b;
}
$result = divide(10, 2);
if ($result !== false) {
echo "结果:$result";
} else {
echo "除数不能为零";
}
// 提前返回
function processUser($user) {
if (empty($user)) {
return null;
}
if (!isset($user['email'])) {
return false;
}
// 处理用户逻辑
return $user;
}
?>
4.3.2 多值返回
<?php
// 使用数组返回多个值
function getNameAndAge() {
return ['张三', 25];
}
// 使用list()解构
list($name, $age) = getNameAndAge();
echo "姓名:$name,年龄:$age\n";
// PHP 7.1+ 使用数组解构
[$name, $age] = getNameAndAge();
// 返回关联数组
function getUserInfo() {
return [
'name' => '张三',
'age' => 25,
'email' => 'zhangsan@example.com'
];
}
// 解构关联数组
['name' => $userName, 'age' => $userAge] = getUserInfo();
// 使用对象返回多个值
class UserInfo {
public $name;
public $age;
public $email;
public function __construct($name, $age, $email) {
$this->name = $name;
$this->age = $age;
$this->email = $email;
}
}
function createUserInfo() {
return new UserInfo('张三', 25, 'zhangsan@example.com');
}
$userInfo = createUserInfo();
echo $userInfo->name;
// 使用生成器返回多个值
function getMultipleValues() {
yield 'first';
yield 'second';
yield 'third';
}
foreach (getMultipleValues() as $value) {
echo $value . "\n";
}
?>
4.3.3 返回类型声明(PHP 7+)
<?php
// 基本返回类型声明
function getString(): string {
return "Hello World";
}
function getInteger(): int {
return 42;
}
function getFloat(): float {
return 3.14;
}
function getBoolean(): bool {
return true;
}
function getArray(): array {
return [1, 2, 3];
}
// 可空返回类型(PHP 7.1+)
function findUser($id): ?User {
if ($id > 0) {
return new User();
}
return null;
}
// 联合类型(PHP 8+)
function getValue(): int|string {
if (rand(0, 1)) {
return 42;
}
return "Hello";
}
// void返回类型
function logMessage(string $message): void {
echo $message . "\n";
// 不能有return语句,或者只能是return;
}
// never返回类型(PHP 8.1+)
function throwException(): never {
throw new Exception('This function never returns');
}
// 自定义类返回类型
class User {
public $name;
}
function createUser(): User {
return new User();
}
// 接口返回类型
interface UserInterface {
public function getName(): string;
}
function getUser(): UserInterface {
return new User();
}
?>
4.4 变量作用域
4.4.1 局部作用域
<?php
$globalVar = "全局变量";
function testLocalScope() {
$localVar = "局部变量";
echo $localVar; // 可以访问
// echo $globalVar; // 错误:无法访问全局变量
}
testLocalScope();
// echo $localVar; // 错误:无法访问局部变量
// 函数参数也是局部变量
function processData($data) {
$data = strtoupper($data); // 修改局部副本
echo $data;
}
$myData = "hello";
processData($myData);
echo $myData; // 仍然是"hello"
?>
4.4.2 全局作用域
<?php
$globalVar = "全局变量";
$anotherGlobal = "另一个全局变量";
function accessGlobal() {
global $globalVar;
echo $globalVar; // 可以访问
$globalVar = "修改后的全局变量";
}
accessGlobal();
echo $globalVar; // 输出:修改后的全局变量
// 使用$GLOBALS数组
function accessGlobalArray() {
echo $GLOBALS['anotherGlobal'];
$GLOBALS['anotherGlobal'] = "通过GLOBALS修改";
}
accessGlobalArray();
echo $anotherGlobal; // 输出:通过GLOBALS修改
// 在函数中创建全局变量
function createGlobal() {
global $newGlobal;
$newGlobal = "新的全局变量";
}
createGlobal();
echo $newGlobal; // 输出:新的全局变量
?>
4.4.3 静态作用域
<?php
// 静态变量
function counter() {
static $count = 0;
$count++;
echo "调用次数:$count\n";
}
counter(); // 调用次数:1
counter(); // 调用次数:2
counter(); // 调用次数:3
// 静态变量的初始化
function fibonacci($n) {
static $cache = [];
if (isset($cache[$n])) {
return $cache[$n];
}
if ($n <= 1) {
$cache[$n] = $n;
} else {
$cache[$n] = fibonacci($n - 1) + fibonacci($n - 2);
}
return $cache[$n];
}
echo fibonacci(10); // 使用缓存提高性能
// 多个静态变量
function statistics($value = null) {
static $sum = 0;
static $count = 0;
static $values = [];
if ($value !== null) {
$sum += $value;
$count++;
$values[] = $value;
}
return [
'sum' => $sum,
'count' => $count,
'average' => $count > 0 ? $sum / $count : 0,
'values' => $values
];
}
statistics(10);
statistics(20);
statistics(30);
print_r(statistics()); // 获取统计信息
?>
4.4.4 超全局变量
<?php
// 超全局变量在任何作用域都可以访问
function showSuperglobals() {
echo "GET参数:";
print_r($_GET);
echo "POST参数:";
print_r($_POST);
echo "SESSION数据:";
print_r($_SESSION);
echo "COOKIE数据:";
print_r($_COOKIE);
echo "服务器信息:";
echo $_SERVER['HTTP_HOST'] . "\n";
echo $_SERVER['REQUEST_URI'] . "\n";
echo "环境变量:";
echo $_ENV['PATH'] ?? '未设置';
echo "文件上传:";
print_r($_FILES);
echo "请求数据:";
print_r($_REQUEST); // 包含GET、POST、COOKIE
}
// 自定义超全局变量(不推荐)
$GLOBALS['myGlobal'] = "自定义全局变量";
function accessCustomGlobal() {
echo $GLOBALS['myGlobal'];
}
?>
4.5 匿名函数和闭包
4.5.1 匿名函数
<?php
// 基本匿名函数
$greet = function($name) {
return "Hello, $name!";
};
echo $greet("张三"); // 输出:Hello, 张三!
// 将匿名函数作为参数传递
function processArray($array, $callback) {
$result = [];
foreach ($array as $item) {
$result[] = $callback($item);
}
return $result;
}
$numbers = [1, 2, 3, 4, 5];
// 使用匿名函数计算平方
$squares = processArray($numbers, function($n) {
return $n * $n;
});
print_r($squares); // [1, 4, 9, 16, 25]
// 使用匿名函数过滤数组
$evenNumbers = array_filter($numbers, function($n) {
return $n % 2 === 0;
});
print_r($evenNumbers); // [2, 4]
// 使用匿名函数排序
$users = [
['name' => '张三', 'age' => 25],
['name' => '李四', 'age' => 30],
['name' => '王五', 'age' => 20]
];
usort($users, function($a, $b) {
return $a['age'] - $b['age'];
});
print_r($users); // 按年龄排序
?>
4.5.2 闭包
<?php
// 使用use关键字创建闭包
$message = "Hello";
$name = "张三";
$greet = function() use ($message, $name) {
return "$message, $name!";
};
echo $greet(); // 输出:Hello, 张三!
// 通过引用捕获变量
$counter = 0;
$increment = function() use (&$counter) {
$counter++;
return $counter;
};
echo $increment(); // 1
echo $increment(); // 2
echo $counter; // 2
// 创建计数器工厂
function createCounter($start = 0) {
return function() use (&$start) {
return ++$start;
};
}
$counter1 = createCounter(10);
$counter2 = createCounter(100);
echo $counter1(); // 11
echo $counter1(); // 12
echo $counter2(); // 101
echo $counter2(); // 102
// 使用闭包实现私有变量
function createBankAccount($initialBalance) {
$balance = $initialBalance;
return [
'deposit' => function($amount) use (&$balance) {
if ($amount > 0) {
$balance += $amount;
return $balance;
}
return false;
},
'withdraw' => function($amount) use (&$balance) {
if ($amount > 0 && $amount <= $balance) {
$balance -= $amount;
return $balance;
}
return false;
},
'getBalance' => function() use (&$balance) {
return $balance;
}
];
}
$account = createBankAccount(1000);
echo $account['deposit'](500); // 1500
echo $account['withdraw'](200); // 1300
echo $account['getBalance'](); // 1300
?>
4.5.3 箭头函数(PHP 7.4+)
<?php
// 箭头函数语法
$numbers = [1, 2, 3, 4, 5];
// 传统匿名函数
$squares1 = array_map(function($n) {
return $n * $n;
}, $numbers);
// 箭头函数
$squares2 = array_map(fn($n) => $n * $n, $numbers);
// 箭头函数自动捕获外部变量
$multiplier = 3;
$results = array_map(fn($n) => $n * $multiplier, $numbers);
// 复杂的箭头函数
$users = [
['name' => '张三', 'age' => 25],
['name' => '李四', 'age' => 30],
['name' => '王五', 'age' => 20]
];
$names = array_map(fn($user) => $user['name'], $users);
$adults = array_filter($users, fn($user) => $user['age'] >= 18);
// 嵌套箭头函数
$matrix = [[1, 2], [3, 4], [5, 6]];
$flattened = array_map(fn($row) => array_map(fn($n) => $n * 2, $row), $matrix);
// 条件箭头函数
$grades = [85, 92, 78, 96, 88];
$levels = array_map(
fn($grade) => $grade >= 90 ? 'A' : ($grade >= 80 ? 'B' : 'C'),
$grades
);
?>
4.6 内置函数
4.6.1 字符串函数
<?php
$text = "Hello World";
// 字符串长度
echo strlen($text); // 11
echo mb_strlen("你好世界"); // 4
// 字符串转换
echo strtoupper($text); // HELLO WORLD
echo strtolower($text); // hello world
echo ucfirst($text); // Hello world
echo ucwords($text); // Hello World
// 字符串查找
echo strpos($text, "World"); // 6
echo strstr($text, "World"); // World
echo substr($text, 6); // World
echo substr($text, 0, 5); // Hello
// 字符串替换
echo str_replace("World", "PHP", $text); // Hello PHP
echo str_ireplace("world", "PHP", $text); // Hello PHP (忽略大小写)
// 字符串分割和连接
$parts = explode(" ", $text); // ["Hello", "World"]
$joined = implode("-", $parts); // "Hello-World"
// 字符串修剪
$padded = " Hello World ";
echo trim($padded); // "Hello World"
echo ltrim($padded); // "Hello World "
echo rtrim($padded); // " Hello World"
// 字符串格式化
printf("姓名:%s,年龄:%d\n", "张三", 25);
$formatted = sprintf("价格:%.2f元", 19.99);
// 字符串验证
var_dump(is_string($text)); // true
var_dump(ctype_alpha("abc")); // true
var_dump(ctype_digit("123")); // true
var_dump(filter_var("test@example.com", FILTER_VALIDATE_EMAIL));
?>
4.6.2 数组函数
<?php
$numbers = [1, 2, 3, 4, 5];
$fruits = ['apple', 'banana', 'orange'];
// 数组信息
echo count($numbers); // 5
echo sizeof($numbers); // 5 (count的别名)
var_dump(empty($numbers)); // false
var_dump(is_array($numbers)); // true
// 数组操作
array_push($fruits, 'grape'); // 添加到末尾
array_unshift($fruits, 'mango'); // 添加到开头
$last = array_pop($fruits); // 移除并返回最后一个
$first = array_shift($fruits); // 移除并返回第一个
// 数组搜索
echo array_search('banana', $fruits); // 返回键名
var_dump(in_array('apple', $fruits)); // true
var_dump(array_key_exists('name', ['name' => '张三'])); // true
// 数组过滤和映射
$evenNumbers = array_filter($numbers, function($n) {
return $n % 2 === 0;
});
$squares = array_map(function($n) {
return $n * $n;
}, $numbers);
// 数组归约
$sum = array_reduce($numbers, function($carry, $item) {
return $carry + $item;
}, 0);
// 数组排序
sort($numbers); // 升序排序
rsort($numbers); // 降序排序
asort($fruits); // 保持键名的升序排序
ksort($fruits); // 按键名排序
// 数组合并和分割
$merged = array_merge($numbers, $fruits);
$chunks = array_chunk($numbers, 2); // 分割成每组2个元素
$sliced = array_slice($numbers, 1, 3); // 从索引1开始取3个元素
// 数组键值操作
$keys = array_keys($fruits);
$values = array_values($fruits);
$flipped = array_flip($fruits); // 键值互换
$combined = array_combine(['a', 'b', 'c'], [1, 2, 3]);
?>
4.6.3 数学函数
<?php
// 基本数学函数
echo abs(-5); // 5
echo ceil(4.3); // 5
echo floor(4.7); // 4
echo round(4.6); // 5
echo round(4.567, 2); // 4.57
// 最大值和最小值
echo max(1, 3, 2); // 3
echo min(1, 3, 2); // 1
echo max([1, 3, 2]); // 3
// 幂运算
echo pow(2, 3); // 8
echo sqrt(16); // 4
echo exp(1); // e
echo log(10); // 自然对数
echo log10(100); // 2
// 三角函数
echo sin(M_PI / 2); // 1
echo cos(0); // 1
echo tan(M_PI / 4); // 1
// 随机数
echo rand(); // 随机整数
echo rand(1, 10); // 1-10之间的随机整数
echo mt_rand(); // 更好的随机数生成器
echo random_int(1, 100); // 加密安全的随机整数
// 数字格式化
echo number_format(1234567.89); // 1,234,568
echo number_format(1234567.89, 2); // 1,234,567.89
echo number_format(1234567.89, 2, '.', ','); // 1,234,567.89
// 进制转换
echo base_convert('ff', 16, 10); // 255
echo dechex(255); // ff
echo hexdec('ff'); // 255
echo decbin(8); // 1000
echo bindec('1000'); // 8
?>
4.6.4 日期时间函数
<?php
// 当前时间
echo time(); // Unix时间戳
echo date('Y-m-d H:i:s'); // 2024-01-01 12:00:00
echo date('Y-m-d H:i:s', time()); // 指定时间戳
// 日期格式化
echo date('Y年m月d日'); // 2024年01月01日
echo date('l, F j, Y'); // Monday, January 1, 2024
echo date('c'); // ISO 8601格式
echo date('r'); // RFC 2822格式
// 时间解析
$timestamp = strtotime('2024-01-01 12:00:00');
$timestamp = strtotime('+1 day');
$timestamp = strtotime('next Monday');
$timestamp = strtotime('last Friday');
// 日期计算
echo date('Y-m-d', strtotime('+1 week'));
echo date('Y-m-d', strtotime('-1 month'));
echo date('Y-m-d', strtotime('+1 year'));
// 日期信息
$info = getdate();
echo $info['year']; // 年
echo $info['mon']; // 月
echo $info['mday']; // 日
echo $info['hours']; // 小时
echo $info['minutes']; // 分钟
echo $info['seconds']; // 秒
// 检查日期有效性
var_dump(checkdate(2, 29, 2024)); // true (闰年)
var_dump(checkdate(2, 29, 2023)); // false (非闰年)
// 时区设置
date_default_timezone_set('Asia/Shanghai');
echo date_default_timezone_get();
// DateTime类(面向对象方式)
$date = new DateTime();
echo $date->format('Y-m-d H:i:s');
$date->add(new DateInterval('P1D')); // 加1天
echo $date->format('Y-m-d H:i:s');
$date->sub(new DateInterval('PT1H')); // 减1小时
echo $date->format('Y-m-d H:i:s');
?>
4.7 递归函数
4.7.1 基本递归
<?php
// 计算阶乘
function factorial($n) {
// 基础情况
if ($n <= 1) {
return 1;
}
// 递归情况
return $n * factorial($n - 1);
}
echo factorial(5); // 120
// 斐波那契数列
function fibonacci($n) {
if ($n <= 1) {
return $n;
}
return fibonacci($n - 1) + fibonacci($n - 2);
}
echo fibonacci(10); // 55
// 优化的斐波那契(使用记忆化)
function fibonacciMemo($n, &$memo = []) {
if (isset($memo[$n])) {
return $memo[$n];
}
if ($n <= 1) {
$memo[$n] = $n;
} else {
$memo[$n] = fibonacciMemo($n - 1, $memo) + fibonacciMemo($n - 2, $memo);
}
return $memo[$n];
}
echo fibonacciMemo(50); // 快速计算大数
// 计算最大公约数
function gcd($a, $b) {
if ($b == 0) {
return $a;
}
return gcd($b, $a % $b);
}
echo gcd(48, 18); // 6
?>
4.7.2 树形结构递归
<?php
// 目录遍历
function listDirectory($dir, $level = 0) {
$indent = str_repeat(' ', $level);
if (is_dir($dir)) {
echo $indent . basename($dir) . "/\n";
$files = scandir($dir);
foreach ($files as $file) {
if ($file != '.' && $file != '..') {
listDirectory($dir . '/' . $file, $level + 1);
}
}
} else {
echo $indent . basename($dir) . "\n";
}
}
listDirectory('/path/to/directory');
// 计算目录大小
function getDirectorySize($dir) {
$size = 0;
if (is_dir($dir)) {
$files = scandir($dir);
foreach ($files as $file) {
if ($file != '.' && $file != '..') {
$path = $dir . '/' . $file;
if (is_dir($path)) {
$size += getDirectorySize($path);
} else {
$size += filesize($path);
}
}
}
}
return $size;
}
// 数组递归处理
function arraySum($array) {
$sum = 0;
foreach ($array as $value) {
if (is_array($value)) {
$sum += arraySum($value); // 递归处理子数组
} else {
$sum += $value;
}
}
return $sum;
}
$nestedArray = [1, [2, 3], [4, [5, 6]], 7];
echo arraySum($nestedArray); // 28
// 多维数组扁平化
function flattenArray($array) {
$result = [];
foreach ($array as $value) {
if (is_array($value)) {
$result = array_merge($result, flattenArray($value));
} else {
$result[] = $value;
}
}
return $result;
}
$nested = [1, [2, 3], [4, [5, 6]], 7];
$flat = flattenArray($nested);
print_r($flat); // [1, 2, 3, 4, 5, 6, 7]
?>
4.7.3 递归优化
<?php
// 尾递归优化(PHP不支持尾递归优化,但可以手动转换为循环)
// 递归版本(可能栈溢出)
function factorialRecursive($n) {
if ($n <= 1) {
return 1;
}
return $n * factorialRecursive($n - 1);
}
// 尾递归版本
function factorialTailRecursive($n, $accumulator = 1) {
if ($n <= 1) {
return $accumulator;
}
return factorialTailRecursive($n - 1, $n * $accumulator);
}
// 循环版本(推荐)
function factorialIterative($n) {
$result = 1;
for ($i = 2; $i <= $n; $i++) {
$result *= $i;
}
return $result;
}
// 使用栈模拟递归
function factorialStack($n) {
$stack = [];
$result = 1;
// 将所有数字压入栈
for ($i = $n; $i > 1; $i--) {
array_push($stack, $i);
}
// 从栈中弹出并计算
while (!empty($stack)) {
$result *= array_pop($stack);
}
return $result;
}
// 递归深度限制
function limitedRecursion($n, $depth = 0, $maxDepth = 1000) {
if ($depth > $maxDepth) {
throw new Exception('递归深度超过限制');
}
if ($n <= 1) {
return 1;
}
return $n * limitedRecursion($n - 1, $depth + 1, $maxDepth);
}
?>
4.8 函数式编程
4.8.1 高阶函数
<?php
// 函数作为参数
function applyOperation($a, $b, $operation) {
return $operation($a, $b);
}
$add = function($x, $y) { return $x + $y; };
$multiply = function($x, $y) { return $x * $y; };
echo applyOperation(5, 3, $add); // 8
echo applyOperation(5, 3, $multiply); // 15
// 函数作为返回值
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 compose($f, $g) {
return function($x) use ($f, $g) {
return $f($g($x));
};
}
$addOne = function($x) { return $x + 1; };
$multiplyTwo = function($x) { return $x * 2; };
$addThenMultiply = compose($multiplyTwo, $addOne);
echo $addThenMultiply(5); // (5 + 1) * 2 = 12
// 柯里化
function curry($func) {
return function($a) use ($func) {
return function($b) use ($func, $a) {
return $func($a, $b);
};
};
}
$curriedAdd = curry(function($a, $b) { return $a + $b; });
$addFive = $curriedAdd(5);
echo $addFive(3); // 8
?>
4.8.2 数组函数式操作
<?php
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 链式操作
$result = array_filter(
array_map(
function($n) { return $n * 2; },
$numbers
),
function($n) { return $n > 10; }
);
print_r($result); // [12, 14, 16, 18, 20]
// 自定义链式操作类
class ArrayPipeline {
private $data;
public function __construct($data) {
$this->data = $data;
}
public function map($callback) {
$this->data = array_map($callback, $this->data);
return $this;
}
public function filter($callback) {
$this->data = array_filter($this->data, $callback);
return $this;
}
public function reduce($callback, $initial = null) {
return array_reduce($this->data, $callback, $initial);
}
public function toArray() {
return array_values($this->data);
}
}
$pipeline = new ArrayPipeline([1, 2, 3, 4, 5]);
$result = $pipeline
->map(fn($n) => $n * 2)
->filter(fn($n) => $n > 5)
->toArray();
print_r($result); // [6, 8, 10]
// 函数式编程工具函数
function pipe(...$functions) {
return function($value) use ($functions) {
return array_reduce($functions, function($carry, $func) {
return $func($carry);
}, $value);
};
}
$transform = pipe(
fn($n) => $n * 2,
fn($n) => $n + 1,
fn($n) => $n / 3
);
echo $transform(5); // ((5 * 2) + 1) / 3 = 3.67
?>
4.9 小结
本章详细介绍了PHP函数的各个方面:
- 函数基础:定义、调用、命名规则、文档注释
- 参数传递:值传递、引用传递、默认参数、可变参数、命名参数
- 返回值:基本返回、多值返回、类型声明
- 变量作用域:局部、全局、静态、超全局变量
- 匿名函数和闭包:匿名函数、闭包、箭头函数
- 内置函数:字符串、数组、数学、日期时间函数
- 递归函数:基本递归、树形结构、递归优化
- 函数式编程:高阶函数、函数组合、链式操作
4.10 实践练习
基础函数练习:
- 编写各种计算函数(面积、体积等)
- 实现字符串处理函数
- 创建数据验证函数
高级特性练习:
- 使用闭包实现计数器
- 编写递归函数处理树形数据
- 实现函数式编程工具
实际应用练习:
- 创建用户认证系统
- 实现数据处理管道
- 编写文件操作工具函数
性能优化练习:
- 优化递归函数
- 实现函数缓存机制
- 比较不同实现方式的性能
4.11 扩展阅读
下一章预告:在下一章中,我们将学习PHP的数组,包括索引数组、关联数组、多维数组以及各种数组操作函数。