本章目标

  • 掌握数组的基本概念和类型
  • 学会创建和初始化数组
  • 理解索引数组和关联数组的区别
  • 掌握多维数组的使用
  • 学会数组的遍历方法
  • 掌握常用数组函数
  • 了解数组的高级操作

5.1 数组基础

5.1.1 数组概念

<?php
// 数组是一个有序的映射,将值关联到键
// PHP中的数组实际上是一个有序映射

// 什么是数组?
// - 存储多个值的变量
// - 每个值都有一个键(索引)
// - 键可以是整数或字符串
// - 值可以是任何数据类型

// 数组的特点:
// 1. 动态大小
// 2. 混合数据类型
// 3. 键值对结构
// 4. 有序性

echo "PHP数组示例:\n";

// 简单数组示例
$fruits = ['apple', 'banana', 'orange'];
print_r($fruits);

// 关联数组示例
$person = [
    'name' => '张三',
    'age' => 25,
    'email' => 'zhangsan@example.com'
];
print_r($person);
?>

5.1.2 数组类型

<?php
// 1. 索引数组(数值索引)
$indexedArray = [1, 2, 3, 4, 5];
$colors = ['red', 'green', 'blue'];

echo "索引数组:\n";
print_r($indexedArray);
print_r($colors);

// 2. 关联数组(字符串索引)
$associativeArray = [
    'name' => '李四',
    'age' => 30,
    'city' => '北京'
];

echo "关联数组:\n";
print_r($associativeArray);

// 3. 混合数组(数值和字符串索引混合)
$mixedArray = [
    0 => 'first',
    'name' => '王五',
    1 => 'second',
    'age' => 28
];

echo "混合数组:\n";
print_r($mixedArray);

// 4. 多维数组
$multiArray = [
    ['张三', 25, '北京'],
    ['李四', 30, '上海'],
    ['王五', 28, '广州']
];

echo "多维数组:\n";
print_r($multiArray);

// 5. 嵌套关联数组
$nestedArray = [
    'users' => [
        [
            'name' => '张三',
            'profile' => [
                'age' => 25,
                'address' => [
                    'city' => '北京',
                    'district' => '朝阳区'
                ]
            ]
        ]
    ]
];

echo "嵌套关联数组:\n";
print_r($nestedArray);
?>

5.2 数组创建和初始化

5.2.1 创建数组的方法

<?php
// 方法1:使用array()函数
$array1 = array(1, 2, 3, 4, 5);
$array2 = array(
    'name' => '张三',
    'age' => 25
);

// 方法2:使用短数组语法[](PHP 5.4+)
$array3 = [1, 2, 3, 4, 5];
$array4 = [
    'name' => '李四',
    'age' => 30
];

// 方法3:逐个赋值
$array5 = [];
$array5[0] = 'first';
$array5[1] = 'second';
$array5['name'] = '王五';

// 方法4:使用range()函数
$numbers = range(1, 10);        // [1, 2, 3, ..., 10]
$letters = range('a', 'z');     // ['a', 'b', 'c', ..., 'z']
$evens = range(2, 20, 2);       // [2, 4, 6, ..., 20]

echo "range()创建的数组:\n";
print_r($numbers);
print_r($letters);
print_r($evens);

// 方法5:使用array_fill()函数
$filled = array_fill(0, 5, 'default'); // 5个'default'值
$keys = array_fill_keys(['a', 'b', 'c'], 0); // 指定键名

echo "array_fill()创建的数组:\n";
print_r($filled);
print_r($keys);

// 方法6:从字符串创建
$string = "apple,banana,orange";
$fruits = explode(',', $string);

echo "从字符串创建的数组:\n";
print_r($fruits);

// 方法7:从其他数组创建
$original = [1, 2, 3];
$copy = $original;              // 复制
$slice = array_slice($original, 1, 2); // 切片

echo "从其他数组创建:\n";
print_r($copy);
print_r($slice);
?>

5.2.2 数组初始化技巧

<?php
// 1. 预定义大小的数组
function createFixedArray($size, $defaultValue = null) {
    return array_fill(0, $size, $defaultValue);
}

$fixedArray = createFixedArray(10, 0);
echo "固定大小数组:\n";
print_r($fixedArray);

// 2. 二维数组初始化
function create2DArray($rows, $cols, $defaultValue = 0) {
    $array = [];
    for ($i = 0; $i < $rows; $i++) {
        $array[$i] = array_fill(0, $cols, $defaultValue);
    }
    return $array;
}

$matrix = create2DArray(3, 4, 0);
echo "二维数组:\n";
print_r($matrix);

// 3. 使用回调函数初始化
function initializeWithCallback($size, $callback) {
    $array = [];
    for ($i = 0; $i < $size; $i++) {
        $array[$i] = $callback($i);
    }
    return $array;
}

$squares = initializeWithCallback(5, function($i) {
    return $i * $i;
});

echo "使用回调初始化:\n";
print_r($squares);

// 4. 条件初始化
$conditionalArray = [];
for ($i = 1; $i <= 20; $i++) {
    if ($i % 2 === 0) {
        $conditionalArray[] = $i;
    }
}

echo "条件初始化(偶数):\n";
print_r($conditionalArray);

// 5. 从配置文件初始化
$config = [
    'database' => [
        'host' => 'localhost',
        'port' => 3306,
        'username' => 'root',
        'password' => '',
        'database' => 'test'
    ],
    'cache' => [
        'driver' => 'redis',
        'host' => '127.0.0.1',
        'port' => 6379
    ]
];

echo "配置数组:\n";
print_r($config);

// 6. 使用生成器初始化大数组
function generateLargeArray($size) {
    for ($i = 0; $i < $size; $i++) {
        yield $i => $i * 2;
    }
}

// 转换为数组
$largeArray = iterator_to_array(generateLargeArray(1000));
echo "大数组前10个元素:\n";
print_r(array_slice($largeArray, 0, 10, true));
?>

5.3 数组访问和修改

5.3.1 数组元素访问

<?php
$fruits = ['apple', 'banana', 'orange', 'grape'];
$person = [
    'name' => '张三',
    'age' => 25,
    'email' => 'zhangsan@example.com'
];

// 1. 基本访问
echo "第一个水果:" . $fruits[0] . "\n";        // apple
echo "姓名:" . $person['name'] . "\n";         // 张三

// 2. 检查键是否存在
if (isset($fruits[1])) {
    echo "第二个水果:" . $fruits[1] . "\n";
}

if (array_key_exists('age', $person)) {
    echo "年龄:" . $person['age'] . "\n";
}

// 3. 使用null合并操作符(PHP 7+)
echo "电话:" . ($person['phone'] ?? '未提供') . "\n";

// 4. 动态键访问
$key = 'email';
echo "邮箱:" . $person[$key] . "\n";

// 5. 多维数组访问
$users = [
    [
        'name' => '张三',
        'profile' => [
            'age' => 25,
            'address' => [
                'city' => '北京',
                'district' => '朝阳区'
            ]
        ]
    ]
];

echo "用户姓名:" . $users[0]['name'] . "\n";
echo "用户年龄:" . $users[0]['profile']['age'] . "\n";
echo "用户城市:" . $users[0]['profile']['address']['city'] . "\n";

// 6. 安全的多维数组访问
function getNestedValue($array, $keys, $default = null) {
    foreach ($keys as $key) {
        if (is_array($array) && array_key_exists($key, $array)) {
            $array = $array[$key];
        } else {
            return $default;
        }
    }
    return $array;
}

$city = getNestedValue($users, [0, 'profile', 'address', 'city'], '未知');
echo "安全访问城市:" . $city . "\n";

// 7. 使用变量变量访问
$arrayName = 'fruits';
$index = 0;
echo "变量变量访问:" . ${$arrayName}[$index] . "\n";
?>

5.3.2 数组元素修改

<?php
$fruits = ['apple', 'banana', 'orange'];
$person = ['name' => '张三', 'age' => 25];

// 1. 直接修改
$fruits[1] = 'mango';           // 修改现有元素
$fruits[3] = 'grape';           // 添加新元素
$person['age'] = 26;            // 修改现有元素
$person['email'] = 'zhangsan@example.com'; // 添加新元素

echo "修改后的数组:\n";
print_r($fruits);
print_r($person);

// 2. 使用array_push()添加元素
array_push($fruits, 'kiwi', 'pear');
echo "使用array_push()后:\n";
print_r($fruits);

// 3. 使用[]操作符添加元素
$fruits[] = 'watermelon';
echo "使用[]添加后:\n";
print_r($fruits);

// 4. 使用array_unshift()在开头添加
array_unshift($fruits, 'strawberry');
echo "在开头添加后:\n";
print_r($fruits);

// 5. 删除元素
unset($fruits[2]);              // 删除指定索引
unset($person['email']);        // 删除指定键

echo "删除元素后:\n";
print_r($fruits);
print_r($person);

// 6. 使用array_pop()和array_shift()
$lastFruit = array_pop($fruits);    // 删除并返回最后一个
$firstFruit = array_shift($fruits); // 删除并返回第一个

echo "删除的水果:$lastFruit, $firstFruit\n";
echo "删除后的数组:\n";
print_r($fruits);

// 7. 批量修改
$numbers = [1, 2, 3, 4, 5];

// 使用array_map()修改所有元素
$doubled = array_map(function($n) {
    return $n * 2;
}, $numbers);

echo "翻倍后的数组:\n";
print_r($doubled);

// 8. 条件修改
$scores = [85, 92, 78, 96, 88];

for ($i = 0; $i < count($scores); $i++) {
    if ($scores[$i] < 80) {
        $scores[$i] += 5; // 给低分加5分
    }
}

echo "调整后的分数:\n";
print_r($scores);

// 9. 多维数组修改
$users = [
    ['name' => '张三', 'age' => 25],
    ['name' => '李四', 'age' => 30]
];

$users[0]['age'] = 26;          // 修改嵌套值
$users[1]['email'] = 'lisi@example.com'; // 添加嵌套值

echo "修改后的用户数组:\n";
print_r($users);
?>

5.4 数组遍历

5.4.1 基本遍历方法

<?php
$fruits = ['apple', 'banana', 'orange', 'grape'];
$person = [
    'name' => '张三',
    'age' => 25,
    'email' => 'zhangsan@example.com'
];

// 1. for循环(仅适用于数值索引数组)
echo "使用for循环:\n";
for ($i = 0; $i < count($fruits); $i++) {
    echo "$i: {$fruits[$i]}\n";
}

// 2. foreach循环(推荐)
echo "\n使用foreach循环(值):\n";
foreach ($fruits as $fruit) {
    echo "$fruit\n";
}

echo "\n使用foreach循环(键值):\n";
foreach ($person as $key => $value) {
    echo "$key: $value\n";
}

// 3. while循环配合each()(PHP 7.2后废弃)
// 使用current(), key(), next()替代
echo "\n使用while循环:\n";
reset($fruits); // 重置内部指针
while (($value = current($fruits)) !== false) {
    $key = key($fruits);
    echo "$key: $value\n";
    next($fruits);
}

// 4. 使用array_walk()
echo "\n使用array_walk():\n";
array_walk($person, function($value, $key) {
    echo "$key: $value\n";
});

// 5. 使用array_map()(返回新数组)
echo "\n使用array_map():\n";
$upperFruits = array_map('strtoupper', $fruits);
print_r($upperFruits);

// 6. 递归遍历多维数组
function printArrayRecursive($array, $level = 0) {
    $indent = str_repeat('  ', $level);
    
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            echo "{$indent}$key:\n";
            printArrayRecursive($value, $level + 1);
        } else {
            echo "{$indent}$key: $value\n";
        }
    }
}

$nestedArray = [
    'user' => [
        'name' => '张三',
        'profile' => [
            'age' => 25,
            'address' => [
                'city' => '北京',
                'district' => '朝阳区'
            ]
        ]
    ]
];

echo "\n递归遍历多维数组:\n";
printArrayRecursive($nestedArray);
?>

5.4.2 高级遍历技巧

<?php
$products = [
    ['name' => '笔记本', 'price' => 5000, 'category' => '电子'],
    ['name' => '手机', 'price' => 3000, 'category' => '电子'],
    ['name' => '书籍', 'price' => 50, 'category' => '图书'],
    ['name' => '衣服', 'price' => 200, 'category' => '服装']
];

// 1. 条件遍历
echo "价格大于1000的产品:\n";
foreach ($products as $product) {
    if ($product['price'] > 1000) {
        echo "{$product['name']}: {$product['price']}元\n";
    }
}

// 2. 分组遍历
$groupedProducts = [];
foreach ($products as $product) {
    $category = $product['category'];
    $groupedProducts[$category][] = $product;
}

echo "\n按类别分组:\n";
foreach ($groupedProducts as $category => $items) {
    echo "$category:\n";
    foreach ($items as $item) {
        echo "  {$item['name']}: {$item['price']}元\n";
    }
}

// 3. 带索引的遍历
echo "\n带索引的遍历:\n";
foreach ($products as $index => $product) {
    echo "第" . ($index + 1) . "个产品:{$product['name']}\n";
}

// 4. 引用遍历(修改原数组)
echo "\n给所有产品打9折:\n";
foreach ($products as &$product) {
    $product['price'] *= 0.9;
}
unset($product); // 取消引用

foreach ($products as $product) {
    echo "{$product['name']}: {$product['price']}元\n";
}

// 5. 多数组同时遍历
$names = ['张三', '李四', '王五'];
$ages = [25, 30, 28];
$cities = ['北京', '上海', '广州'];

echo "\n多数组同时遍历:\n";
$count = min(count($names), count($ages), count($cities));
for ($i = 0; $i < $count; $i++) {
    echo "{$names[$i]}, {$ages[$i]}岁, 来自{$cities[$i]}\n";
}

// 6. 使用ArrayIterator
echo "\n使用ArrayIterator:\n";
$iterator = new ArrayIterator($products);
while ($iterator->valid()) {
    $product = $iterator->current();
    $index = $iterator->key();
    echo "索引$index: {$product['name']}\n";
    $iterator->next();
}

// 7. 自定义遍历函数
function forEachWithBreak($array, $callback) {
    foreach ($array as $key => $value) {
        $result = $callback($value, $key);
        if ($result === false) {
            break;
        }
    }
}

echo "\n自定义遍历(找到第一个电子产品就停止):\n";
forEachWithBreak($products, function($product, $index) {
    echo "检查:{$product['name']}\n";
    if ($product['category'] === '电子') {
        echo "找到电子产品:{$product['name']}\n";
        return false; // 停止遍历
    }
    return true;
});
?>

5.5 数组函数

5.5.1 数组信息函数

<?php
$fruits = ['apple', 'banana', 'orange'];
$numbers = [1, 2, 3, 4, 5];
$mixed = [1, 'hello', 3.14, true, null];
$empty = [];

// 1. 数组长度和大小
echo "数组长度:\n";
echo "count(fruits): " . count($fruits) . "\n";        // 3
echo "sizeof(numbers): " . sizeof($numbers) . "\n";    // 5 (count的别名)
echo "count(empty): " . count($empty) . "\n";          // 0

// 2. 数组类型检查
echo "\n数组类型检查:\n";
var_dump(is_array($fruits));        // true
var_dump(is_array('not array'));    // false

// 3. 数组空值检查
echo "\n数组空值检查:\n";
var_dump(empty($empty));            // true
var_dump(empty($fruits));           // false

// 4. 键和值的存在性检查
echo "\n键和值的存在性检查:\n";
var_dump(array_key_exists(1, $fruits));        // true
var_dump(array_key_exists(5, $fruits));        // false
var_dump(in_array('apple', $fruits));          // true
var_dump(in_array('grape', $fruits));          // false

// 5. 搜索函数
echo "\n搜索函数:\n";
echo "array_search('banana', fruits): " . array_search('banana', $fruits) . "\n"; // 1
var_dump(array_search('grape', $fruits));      // false

// 6. 数组键和值
echo "\n数组键和值:\n";
print_r(array_keys($fruits));       // [0, 1, 2]
print_r(array_values($fruits));     // ['apple', 'banana', 'orange']

$person = ['name' => '张三', 'age' => 25];
print_r(array_keys($person));       // ['name', 'age']
print_r(array_values($person));     // ['张三', 25]

// 7. 数组统计
echo "\n数组统计:\n";
print_r(array_count_values(['a', 'b', 'a', 'c', 'b', 'a'])); // 统计值出现次数

// 8. 数组唯一性
echo "\n数组唯一性:\n";
$duplicates = [1, 2, 2, 3, 3, 3, 4];
print_r(array_unique($duplicates)); // [1, 2, 3, 4]

// 9. 数组比较
echo "\n数组比较:\n";
$array1 = [1, 2, 3];
$array2 = [1, 2, 3];
$array3 = [3, 2, 1];

var_dump($array1 == $array2);       // true
var_dump($array1 === $array2);      // true
var_dump($array1 == $array3);       // false

// 10. 数组差集和交集
echo "\n数组差集和交集:\n";
$set1 = [1, 2, 3, 4, 5];
$set2 = [3, 4, 5, 6, 7];

print_r(array_diff($set1, $set2));      // [1, 2]
print_r(array_intersect($set1, $set2)); // [3, 4, 5]
?>

5.5.2 数组操作函数

<?php
// 1. 数组添加和删除
$fruits = ['apple', 'banana'];

echo "原始数组:\n";
print_r($fruits);

// 在末尾添加
array_push($fruits, 'orange', 'grape');
echo "\narray_push后:\n";
print_r($fruits);

// 在开头添加
array_unshift($fruits, 'mango', 'kiwi');
echo "\narray_unshift后:\n";
print_r($fruits);

// 从末尾删除
$lastFruit = array_pop($fruits);
echo "\n删除的最后一个:$lastFruit\n";
print_r($fruits);

// 从开头删除
$firstFruit = array_shift($fruits);
echo "\n删除的第一个:$firstFruit\n";
print_r($fruits);

// 2. 数组切片和拼接
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

echo "\n数组切片:\n";
print_r(array_slice($numbers, 2, 4));      // [3, 4, 5, 6]
print_r(array_slice($numbers, -3));        // [8, 9, 10]
print_r(array_slice($numbers, 1, -2));     // [2, 3, 4, 5, 6, 7, 8]

// 数组拼接(删除并插入)
$original = [1, 2, 3, 4, 5];
$removed = array_splice($original, 2, 2, ['a', 'b', 'c']);
echo "\n拼接后的数组:\n";
print_r($original);  // [1, 2, 'a', 'b', 'c', 5]
echo "删除的元素:\n";
print_r($removed);   // [3, 4]

// 3. 数组合并
echo "\n数组合并:\n";
$array1 = [1, 2, 3];
$array2 = [4, 5, 6];
$array3 = ['a' => 'apple', 'b' => 'banana'];
$array4 = ['b' => 'blueberry', 'c' => 'cherry'];

print_r(array_merge($array1, $array2));     // [1, 2, 3, 4, 5, 6]
print_r(array_merge($array3, $array4));     // 后面的值覆盖前面的
print_r($array1 + $array2);                 // [1, 2, 3] (+ 操作符不会重新索引)

// 4. 数组翻转和随机
echo "\n数组翻转和随机:\n";
$original = [1, 2, 3, 4, 5];

print_r(array_reverse($original));          // [5, 4, 3, 2, 1]
print_r(array_flip(['a' => 1, 'b' => 2])); // [1 => 'a', 2 => 'b']

$shuffled = $original;
shuffle($shuffled);                         // 随机打乱
print_r($shuffled);

// 5. 数组填充和重复
echo "\n数组填充和重复:\n";
print_r(array_fill(0, 5, 'default'));      // 5个'default'
print_r(array_fill_keys(['a', 'b', 'c'], 0)); // 指定键名填充
print_r(array_pad([1, 2, 3], 6, 0));       // 填充到指定长度
print_r(array_repeat([1, 2], 3));          // 重复数组

// 6. 数组分块
echo "\n数组分块:\n";
$data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
print_r(array_chunk($data, 3));             // 每3个一组
print_r(array_chunk($data, 3, true));       // 保持键名

// 7. 数组组合
echo "\n数组组合:\n";
$keys = ['name', 'age', 'city'];
$values = ['张三', 25, '北京'];
print_r(array_combine($keys, $values));     // 组合成关联数组
?>

5.5.3 数组排序函数

<?php
// 1. 基本排序
$numbers = [3, 1, 4, 1, 5, 9, 2, 6];
$fruits = ['banana', 'apple', 'orange', 'grape'];

echo "原始数组:\n";
print_r($numbers);
print_r($fruits);

// 升序排序(重新索引)
$sorted1 = $numbers;
sort($sorted1);
echo "\nsort()升序:\n";
print_r($sorted1);

// 降序排序(重新索引)
$sorted2 = $numbers;
rsort($sorted2);
echo "\nrsort()降序:\n";
print_r($sorted2);

// 2. 保持键名的排序
$assoc = ['b' => 2, 'a' => 1, 'd' => 4, 'c' => 3];

echo "\n关联数组原始:\n";
print_r($assoc);

// 按值排序(保持键名)
$sorted3 = $assoc;
asort($sorted3);
echo "\nasort()按值升序:\n";
print_r($sorted3);

// 按值降序排序(保持键名)
$sorted4 = $assoc;
arsort($sorted4);
echo "\narsort()按值降序:\n";
print_r($sorted4);

// 按键排序
$sorted5 = $assoc;
ksort($sorted5);
echo "\nksort()按键升序:\n";
print_r($sorted5);

// 按键降序排序
$sorted6 = $assoc;
krsort($sorted6);
echo "\nkrsort()按键降序:\n";
print_r($sorted6);

// 3. 自定义排序
$students = [
    ['name' => '张三', 'score' => 85],
    ['name' => '李四', 'score' => 92],
    ['name' => '王五', 'score' => 78],
    ['name' => '赵六', 'score' => 96]
];

echo "\n学生原始数据:\n";
print_r($students);

// 使用usort()按分数排序
$sorted7 = $students;
usort($sorted7, function($a, $b) {
    return $b['score'] - $a['score']; // 降序
});
echo "\n按分数降序排序:\n";
print_r($sorted7);

// 使用uasort()保持键名
$sorted8 = $students;
uasort($sorted8, function($a, $b) {
    return strcmp($a['name'], $b['name']); // 按姓名字母顺序
});
echo "\n按姓名排序(保持键名):\n";
print_r($sorted8);

// 4. 多字段排序
function multiSort($array, $fields) {
    usort($array, function($a, $b) use ($fields) {
        foreach ($fields as $field => $order) {
            $result = 0;
            if (is_numeric($a[$field]) && is_numeric($b[$field])) {
                $result = $a[$field] - $b[$field];
            } else {
                $result = strcmp($a[$field], $b[$field]);
            }
            
            if ($result !== 0) {
                return $order === 'desc' ? -$result : $result;
            }
        }
        return 0;
    });
    return $array;
}

$employees = [
    ['name' => '张三', 'department' => 'IT', 'salary' => 8000],
    ['name' => '李四', 'department' => 'HR', 'salary' => 6000],
    ['name' => '王五', 'department' => 'IT', 'salary' => 9000],
    ['name' => '赵六', 'department' => 'HR', 'salary' => 7000]
];

echo "\n员工原始数据:\n";
print_r($employees);

$sorted9 = multiSort($employees, [
    'department' => 'asc',
    'salary' => 'desc'
]);
echo "\n按部门升序、薪资降序排序:\n";
print_r($sorted9);

// 5. 自然排序
$versions = ['v1.10', 'v1.2', 'v1.1', 'v2.0', 'v1.20'];

echo "\n版本号原始:\n";
print_r($versions);

$sorted10 = $versions;
natsort($sorted10);
echo "\n自然排序:\n";
print_r($sorted10);

$sorted11 = $versions;
natcasesort($sorted11); // 忽略大小写的自然排序
echo "\n忽略大小写的自然排序:\n";
print_r($sorted11);
?>

5.5.4 数组过滤和映射函数

<?php
// 1. array_filter() - 过滤数组
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

echo "原始数组:\n";
print_r($numbers);

// 过滤偶数
$evens = array_filter($numbers, function($n) {
    return $n % 2 === 0;
});
echo "\n偶数:\n";
print_r($evens);

// 过滤大于5的数
$greaterThan5 = array_filter($numbers, function($n) {
    return $n > 5;
});
echo "\n大于5的数:\n";
print_r($greaterThan5);

// 过滤空值
$mixed = [1, '', 0, 'hello', null, false, 'world', []];
$filtered = array_filter($mixed); // 默认过滤"假"值
echo "\n过滤空值后:\n";
print_r($filtered);

// 使用ARRAY_FILTER_USE_KEY过滤键
$assoc = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4];
$keyFiltered = array_filter($assoc, function($key) {
    return in_array($key, ['a', 'c']);
}, ARRAY_FILTER_USE_KEY);
echo "\n按键过滤:\n";
print_r($keyFiltered);

// 使用ARRAY_FILTER_USE_BOTH同时使用键和值
$bothFiltered = array_filter($assoc, function($value, $key) {
    return $value > 2 && $key !== 'd';
}, ARRAY_FILTER_USE_BOTH);
echo "\n按键值过滤:\n";
print_r($bothFiltered);

// 2. array_map() - 映射数组
echo "\n=== array_map() 示例 ===\n";

// 基本映射
$squared = array_map(function($n) {
    return $n * $n;
}, $numbers);
echo "\n平方:\n";
print_r($squared);

// 字符串处理
$words = ['hello', 'world', 'php', 'programming'];
$uppercase = array_map('strtoupper', $words);
echo "\n转大写:\n";
print_r($uppercase);

// 多个数组映射
$names = ['张三', '李四', '王五'];
$ages = [25, 30, 28];
$combined = array_map(function($name, $age) {
    return "$name ($age岁)";
}, $names, $ages);
echo "\n组合信息:\n";
print_r($combined);

// 3. array_reduce() - 归约数组
echo "\n=== array_reduce() 示例 ===\n";

// 求和
$sum = array_reduce($numbers, function($carry, $item) {
    return $carry + $item;
}, 0);
echo "\n数组求和:$sum\n";

// 求最大值
$max = array_reduce($numbers, function($carry, $item) {
    return $item > $carry ? $item : $carry;
}, 0);
echo "最大值:$max\n";

// 字符串连接
$sentence = array_reduce($words, function($carry, $item) {
    return $carry . ' ' . $item;
}, '');
echo "连接字符串:" . trim($sentence) . "\n";

// 构建关联数组
$products = [
    ['id' => 1, 'name' => '笔记本', 'price' => 5000],
    ['id' => 2, 'name' => '手机', 'price' => 3000],
    ['id' => 3, 'name' => '平板', 'price' => 2000]
];

$indexed = array_reduce($products, function($carry, $item) {
    $carry[$item['id']] = $item;
    return $carry;
}, []);
echo "\n按ID索引的产品:\n";
print_r($indexed);

// 4. array_walk() - 遍历数组
echo "\n=== array_walk() 示例 ===\n";

$prices = [100, 200, 300, 400];

// 修改数组值(需要引用)
array_walk($prices, function(&$value, $key) {
    $value *= 1.1; // 涨价10%
});
echo "\n涨价后:\n";
print_r($prices);

// 带额外参数
array_walk($prices, function(&$value, $key, $tax) {
    $value *= (1 + $tax);
}, 0.08); // 8%税率
echo "\n加税后:\n";
print_r($prices);

// 递归遍历
$nested = [
    'user' => [
        'name' => '张三',
        'profile' => [
            'age' => 25,
            'city' => '北京'
        ]
    ]
];

array_walk_recursive($nested, function($value, $key) {
    echo "$key: $value\n";
});

// 5. 组合使用
echo "\n=== 组合使用示例 ===\n";

$students = [
    ['name' => '张三', 'scores' => [85, 90, 88]],
    ['name' => '李四', 'scores' => [92, 87, 95]],
    ['name' => '王五', 'scores' => [78, 82, 80]]
];

// 计算每个学生的平均分,并过滤出平均分大于85的学生
$result = array_filter(
    array_map(function($student) {
        $average = array_sum($student['scores']) / count($student['scores']);
        return [
            'name' => $student['name'],
            'average' => round($average, 2)
        ];
    }, $students),
    function($student) {
        return $student['average'] > 85;
    }
);

echo "平均分大于85的学生:\n";
print_r($result);
?>

5.6 多维数组

5.6.1 创建和访问多维数组

<?php
// 1. 二维数组
$matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

echo "二维数组:\n";
print_r($matrix);

// 访问二维数组元素
echo "\n访问元素:\n";
echo "matrix[1][2] = " . $matrix[1][2] . "\n"; // 6

// 修改二维数组元素
$matrix[0][0] = 10;
echo "修改后 matrix[0][0] = " . $matrix[0][0] . "\n";

// 2. 关联多维数组
$users = [
    [
        'id' => 1,
        'name' => '张三',
        'profile' => [
            'age' => 25,
            'email' => 'zhangsan@example.com',
            'address' => [
                'city' => '北京',
                'district' => '朝阳区',
                'street' => '建国路1号'
            ]
        ],
        'skills' => ['PHP', 'JavaScript', 'MySQL']
    ],
    [
        'id' => 2,
        'name' => '李四',
        'profile' => [
            'age' => 30,
            'email' => 'lisi@example.com',
            'address' => [
                'city' => '上海',
                'district' => '浦东新区',
                'street' => '世纪大道100号'
            ]
        ],
        'skills' => ['Python', 'Django', 'PostgreSQL']
    ]
];

echo "\n用户数据:\n";
print_r($users);

// 访问嵌套数据
echo "\n访问嵌套数据:\n";
echo "第一个用户姓名:" . $users[0]['name'] . "\n";
echo "第一个用户年龄:" . $users[0]['profile']['age'] . "\n";
echo "第一个用户城市:" . $users[0]['profile']['address']['city'] . "\n";
echo "第一个用户第一个技能:" . $users[0]['skills'][0] . "\n";

// 3. 动态创建多维数组
function createMatrix($rows, $cols, $defaultValue = 0) {
    $matrix = [];
    for ($i = 0; $i < $rows; $i++) {
        for ($j = 0; $j < $cols; $j++) {
            $matrix[$i][$j] = $defaultValue;
        }
    }
    return $matrix;
}

$dynamicMatrix = createMatrix(3, 4, 1);
echo "\n动态创建的矩阵:\n";
print_r($dynamicMatrix);

// 4. 三维数组示例
$cube = [
    [ // 第一层
        [1, 2],
        [3, 4]
    ],
    [ // 第二层
        [5, 6],
        [7, 8]
    ]
];

echo "\n三维数组:\n";
print_r($cube);
echo "cube[1][0][1] = " . $cube[1][0][1] . "\n"; // 6

// 5. 表格数据结构
$table = [
    'headers' => ['姓名', '年龄', '城市', '薪资'],
    'rows' => [
        ['张三', 25, '北京', 8000],
        ['李四', 30, '上海', 12000],
        ['王五', 28, '广州', 10000]
    ]
];

echo "\n表格数据:\n";
echo "表头:";
print_r($table['headers']);
echo "数据行:\n";
foreach ($table['rows'] as $index => $row) {
    echo "第" . ($index + 1) . "行:";
    print_r($row);
}
?>

5.6.2 多维数组操作

<?php
// 1. 多维数组遍历
$products = [
    [
        'id' => 1,
        'name' => '笔记本电脑',
        'category' => '电子产品',
        'specs' => [
            'cpu' => 'Intel i7',
            'memory' => '16GB',
            'storage' => '512GB SSD'
        ],
        'prices' => [
            'cost' => 4000,
            'retail' => 6000,
            'discount' => 5500
        ]
    ],
    [
        'id' => 2,
        'name' => '智能手机',
        'category' => '电子产品',
        'specs' => [
            'cpu' => 'Snapdragon 888',
            'memory' => '8GB',
            'storage' => '256GB'
        ],
        'prices' => [
            'cost' => 2000,
            'retail' => 3500,
            'discount' => 3200
        ]
    ]
];

echo "产品信息遍历:\n";
foreach ($products as $product) {
    echo "产品:{$product['name']}\n";
    echo "  规格:\n";
    foreach ($product['specs'] as $spec => $value) {
        echo "    $spec: $value\n";
    }
    echo "  价格:\n";
    foreach ($product['prices'] as $type => $price) {
        echo "    $type: $price元\n";
    }
    echo "\n";
}

// 2. 多维数组搜索
function searchMultiArray($array, $key, $value) {
    $results = [];
    foreach ($array as $index => $item) {
        if (isset($item[$key]) && $item[$key] === $value) {
            $results[] = $item;
        }
    }
    return $results;
}

$electronics = searchMultiArray($products, 'category', '电子产品');
echo "电子产品:\n";
print_r($electronics);

// 3. 多维数组排序
function sortMultiArray($array, $key, $order = 'asc') {
    usort($array, function($a, $b) use ($key, $order) {
        $valueA = $a[$key] ?? 0;
        $valueB = $b[$key] ?? 0;
        
        if ($order === 'desc') {
            return $valueB <=> $valueA;
        }
        return $valueA <=> $valueB;
    });
    return $array;
}

// 按零售价排序
$sortedByPrice = sortMultiArray($products, 'prices');
// 注意:这里需要修改排序逻辑来处理嵌套数组
usort($products, function($a, $b) {
    return $a['prices']['retail'] <=> $b['prices']['retail'];
});

echo "按零售价排序:\n";
foreach ($products as $product) {
    echo "{$product['name']}: {$product['prices']['retail']}元\n";
}

// 4. 多维数组过滤
function filterMultiArray($array, $callback) {
    return array_filter($array, $callback);
}

$expensiveProducts = filterMultiArray($products, function($product) {
    return $product['prices']['retail'] > 5000;
});

echo "\n价格超过5000元的产品:\n";
foreach ($expensiveProducts as $product) {
    echo "{$product['name']}: {$product['prices']['retail']}元\n";
}

// 5. 多维数组转换
function flattenArray($array, $prefix = '') {
    $result = [];
    foreach ($array as $key => $value) {
        $newKey = $prefix ? $prefix . '.' . $key : $key;
        if (is_array($value)) {
            $result = array_merge($result, flattenArray($value, $newKey));
        } else {
            $result[$newKey] = $value;
        }
    }
    return $result;
}

echo "\n扁平化第一个产品:\n";
$flattened = flattenArray($products[0]);
print_r($flattened);

// 6. 多维数组分组
function groupBy($array, $key) {
    $groups = [];
    foreach ($array as $item) {
        $groupKey = $item[$key] ?? 'unknown';
        $groups[$groupKey][] = $item;
    }
    return $groups;
}

$groupedProducts = groupBy($products, 'category');
echo "\n按类别分组:\n";
print_r($groupedProducts);

// 7. 多维数组统计
function getStatistics($array, $path) {
    $values = [];
    foreach ($array as $item) {
        $value = $item;
        foreach (explode('.', $path) as $key) {
            if (isset($value[$key])) {
                $value = $value[$key];
            } else {
                $value = null;
                break;
            }
        }
        if ($value !== null && is_numeric($value)) {
            $values[] = $value;
        }
    }
    
    if (empty($values)) {
        return null;
    }
    
    return [
        'count' => count($values),
        'sum' => array_sum($values),
        'average' => array_sum($values) / count($values),
        'min' => min($values),
        'max' => max($values)
    ];
}

echo "\n零售价统计:\n";
$priceStats = getStatistics($products, 'prices.retail');
print_r($priceStats);
?>

5.6.3 多维数组实际应用

<?php
// 1. 购物车系统
class ShoppingCart {
    private $items = [];
    
    public function addItem($productId, $name, $price, $quantity = 1) {
        if (isset($this->items[$productId])) {
            $this->items[$productId]['quantity'] += $quantity;
        } else {
            $this->items[$productId] = [
                'name' => $name,
                'price' => $price,
                'quantity' => $quantity
            ];
        }
    }
    
    public function removeItem($productId) {
        unset($this->items[$productId]);
    }
    
    public function updateQuantity($productId, $quantity) {
        if (isset($this->items[$productId])) {
            if ($quantity <= 0) {
                $this->removeItem($productId);
            } else {
                $this->items[$productId]['quantity'] = $quantity;
            }
        }
    }
    
    public function getTotal() {
        $total = 0;
        foreach ($this->items as $item) {
            $total += $item['price'] * $item['quantity'];
        }
        return $total;
    }
    
    public function getItems() {
        return $this->items;
    }
    
    public function getItemCount() {
        $count = 0;
        foreach ($this->items as $item) {
            $count += $item['quantity'];
        }
        return $count;
    }
}

$cart = new ShoppingCart();
$cart->addItem(1, '笔记本电脑', 6000, 1);
$cart->addItem(2, '鼠标', 100, 2);
$cart->addItem(3, '键盘', 300, 1);

echo "购物车内容:\n";
foreach ($cart->getItems() as $id => $item) {
    echo "ID: $id, 商品: {$item['name']}, 单价: {$item['price']}元, 数量: {$item['quantity']}\n";
}
echo "总计:{$cart->getTotal()}元\n";
echo "商品总数:{$cart->getItemCount()}件\n\n";

// 2. 学生成绩管理系统
class GradeManager {
    private $students = [];
    
    public function addStudent($id, $name) {
        $this->students[$id] = [
            'name' => $name,
            'subjects' => []
        ];
    }
    
    public function addGrade($studentId, $subject, $score) {
        if (isset($this->students[$studentId])) {
            if (!isset($this->students[$studentId]['subjects'][$subject])) {
                $this->students[$studentId]['subjects'][$subject] = [];
            }
            $this->students[$studentId]['subjects'][$subject][] = $score;
        }
    }
    
    public function getStudentAverage($studentId) {
        if (!isset($this->students[$studentId])) {
            return null;
        }
        
        $totalScore = 0;
        $totalCount = 0;
        
        foreach ($this->students[$studentId]['subjects'] as $scores) {
            $totalScore += array_sum($scores);
            $totalCount += count($scores);
        }
        
        return $totalCount > 0 ? $totalScore / $totalCount : 0;
    }
    
    public function getSubjectAverage($subject) {
        $totalScore = 0;
        $totalCount = 0;
        
        foreach ($this->students as $student) {
            if (isset($student['subjects'][$subject])) {
                $totalScore += array_sum($student['subjects'][$subject]);
                $totalCount += count($student['subjects'][$subject]);
            }
        }
        
        return $totalCount > 0 ? $totalScore / $totalCount : 0;
    }
    
    public function getTopStudents($limit = 3) {
        $averages = [];
        foreach ($this->students as $id => $student) {
            $averages[$id] = [
            'name' => $student['name'],
            'average' => $this->getStudentAverage($id)
        ];
    }
    
    // 按平均分降序排序
    uasort($averages, function($a, $b) {
        return $b['average'] <=> $a['average'];
    });
    
    return array_slice($averages, 0, $limit, true);
}

public function getStudents() {
    return $this->students;
}
}

$gradeManager = new GradeManager();
$gradeManager->addStudent(1, '张三');
$gradeManager->addStudent(2, '李四');
$gradeManager->addStudent(3, '王五');

// 添加成绩
$gradeManager->addGrade(1, '数学', 85);
$gradeManager->addGrade(1, '数学', 90);
$gradeManager->addGrade(1, '英语', 88);
$gradeManager->addGrade(2, '数学', 92);
$gradeManager->addGrade(2, '英语', 85);
$gradeManager->addGrade(3, '数学', 78);
$gradeManager->addGrade(3, '英语', 82);

echo "学生平均分:\n";
foreach ($gradeManager->getStudents() as $id => $student) {
    $average = $gradeManager->getStudentAverage($id);
    echo "{$student['name']}: " . round($average, 2) . "分\n";
}

echo "\n数学平均分:" . round($gradeManager->getSubjectAverage('数学'), 2) . "分\n";
echo "英语平均分:" . round($gradeManager->getSubjectAverage('英语'), 2) . "分\n";

echo "\n前3名学生:\n";
$topStudents = $gradeManager->getTopStudents(3);
foreach ($topStudents as $id => $student) {
    echo "{$student['name']}: " . round($student['average'], 2) . "分\n";
}

// 3. 配置管理系统
$config = [
    'database' => [
        'default' => [
            'driver' => 'mysql',
            'host' => 'localhost',
            'port' => 3306,
            'database' => 'myapp',
            'username' => 'root',
            'password' => '',
            'charset' => 'utf8mb4',
            'options' => [
                'timeout' => 30,
                'retry' => 3
            ]
        ],
        'cache' => [
            'driver' => 'redis',
            'host' => '127.0.0.1',
            'port' => 6379,
            'database' => 0
        ]
    ],
    'mail' => [
        'driver' => 'smtp',
        'host' => 'smtp.gmail.com',
        'port' => 587,
        'encryption' => 'tls',
        'username' => 'user@gmail.com',
        'password' => 'password'
    ],
    'app' => [
        'name' => 'My Application',
        'version' => '1.0.0',
        'debug' => true,
        'timezone' => 'Asia/Shanghai',
        'locale' => 'zh_CN'
    ]
];

function getConfig($path, $default = null) {
    global $config;
    $keys = explode('.', $path);
    $value = $config;
    
    foreach ($keys as $key) {
        if (is_array($value) && array_key_exists($key, $value)) {
            $value = $value[$key];
        } else {
            return $default;
        }
    }
    
    return $value;
}

echo "\n配置示例:\n";
echo "应用名称:" . getConfig('app.name') . "\n";
echo "数据库主机:" . getConfig('database.default.host') . "\n";
echo "邮件驱动:" . getConfig('mail.driver') . "\n";
echo "不存在的配置:" . (getConfig('nonexistent.key', '默认值') ?? '默认值') . "\n";
?>

5.7 数组性能优化

5.7.1 性能考虑

<?php
// 1. 数组大小和内存使用
function measureArrayMemory() {
    $memoryBefore = memory_get_usage();
    
    // 创建大数组
    $largeArray = range(1, 100000);
    
    $memoryAfter = memory_get_usage();
    $memoryUsed = $memoryAfter - $memoryBefore;
    
    echo "数组内存使用:" . number_format($memoryUsed) . " 字节\n";
    echo "数组元素数量:" . count($largeArray) . "\n";
    echo "平均每个元素:" . round($memoryUsed / count($largeArray), 2) . " 字节\n";
}

measureArrayMemory();

// 2. 不同遍历方式的性能比较
function compareLoopPerformance() {
    $array = range(1, 100000);
    $iterations = 1;
    
    // foreach循环
    $start = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        foreach ($array as $value) {
            // 简单操作
            $temp = $value * 2;
        }
    }
    $foreachTime = microtime(true) - $start;
    
    // for循环
    $start = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        $count = count($array);
        for ($j = 0; $j < $count; $j++) {
            $temp = $array[$j] * 2;
        }
    }
    $forTime = microtime(true) - $start;
    
    // array_map
    $start = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        $result = array_map(function($value) {
            return $value * 2;
        }, $array);
    }
    $mapTime = microtime(true) - $start;
    
    echo "\n性能比较({$iterations}次迭代):\n";
    echo "foreach: " . number_format($foreachTime * 1000, 3) . "ms\n";
    echo "for: " . number_format($forTime * 1000, 3) . "ms\n";
    echo "array_map: " . number_format($mapTime * 1000, 3) . "ms\n";
}

compareLoopPerformance();

// 3. 数组查找性能优化
function compareSearchMethods() {
    $array = range(1, 10000);
    $searchValue = 8888;
    $iterations = 1000;
    
    // 使用in_array
    $start = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        $found = in_array($searchValue, $array);
    }
    $inArrayTime = microtime(true) - $start;
    
    // 使用array_search
    $start = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        $index = array_search($searchValue, $array);
    }
    $searchTime = microtime(true) - $start;
    
    // 使用关联数组(哈希表)
    $hashArray = array_flip($array);
    $start = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        $found = isset($hashArray[$searchValue]);
    }
    $hashTime = microtime(true) - $start;
    
    echo "\n查找性能比较({$iterations}次查找):\n";
    echo "in_array: " . number_format($inArrayTime * 1000, 3) . "ms\n";
    echo "array_search: " . number_format($searchTime * 1000, 3) . "ms\n";
    echo "hash lookup: " . number_format($hashTime * 1000, 3) . "ms\n";
}

compareSearchMethods();
?>

5.7.2 优化技巧

<?php
// 1. 预分配数组大小
function createOptimizedArray($size) {
    // 预分配数组
    $array = array_fill(0, $size, null);
    
    // 填充数据
    for ($i = 0; $i < $size; $i++) {
        $array[$i] = $i * 2;
    }
    
    return $array;
}

// 2. 使用引用避免复制
function processArrayByReference(&$array) {
    foreach ($array as &$value) {
        $value *= 2; // 直接修改原数组
    }
    unset($value); // 取消引用
}

$numbers = [1, 2, 3, 4, 5];
processArrayByReference($numbers);
print_r($numbers);

// 3. 批量操作优化
function batchProcess($data, $batchSize = 1000) {
    $batches = array_chunk($data, $batchSize);
    $results = [];
    
    foreach ($batches as $batch) {
        // 批量处理
        $batchResult = array_map(function($item) {
            // 复杂处理逻辑
            return $item * $item;
        }, $batch);
        
        $results = array_merge($results, $batchResult);
    }
    
    return $results;
}

// 4. 缓存计算结果
class ArrayCache {
    private static $cache = [];
    
    public static function memoize($key, $callback) {
        if (!isset(self::$cache[$key])) {
            self::$cache[$key] = $callback();
        }
        return self::$cache[$key];
    }
    
    public static function clearCache() {
        self::$cache = [];
    }
}

function expensiveArrayOperation($array) {
    $key = md5(serialize($array));
    
    return ArrayCache::memoize($key, function() use ($array) {
        // 模拟耗时操作
        usleep(1000); // 1ms
        return array_sum($array);
    });
}

$testArray = [1, 2, 3, 4, 5];
echo "第一次调用:" . expensiveArrayOperation($testArray) . "\n";
echo "第二次调用(缓存):" . expensiveArrayOperation($testArray) . "\n";

// 5. 生成器优化大数据处理
function generateLargeDataset($size) {
    for ($i = 0; $i < $size; $i++) {
        yield $i => $i * $i;
    }
}

function processLargeDataset($size) {
    $sum = 0;
    foreach (generateLargeDataset($size) as $value) {
        $sum += $value;
        if ($sum > 1000000) {
            break; // 提前退出
        }
    }
    return $sum;
}

echo "\n大数据集处理结果:" . processLargeDataset(10000) . "\n";
?>

5.8 数组最佳实践

5.8.1 编码规范

<?php
// 1. 数组命名规范
$users = [];           // 好:复数形式
$userList = [];        // 好:明确表示列表
$userData = [];        // 好:明确数据类型

// 避免
$data = [];           // 不好:太泛化
$arr = [];            // 不好:缩写
$temp = [];           // 不好:临时变量名

// 2. 数组结构一致性
$products = [
    [
        'id' => 1,
        'name' => '产品A',
        'price' => 100.00,
        'category' => '电子'
    ],
    [
        'id' => 2,
        'name' => '产品B',
        'price' => 200.00,
        'category' => '电子'
    ]
];

// 3. 使用常量作为数组键
class ProductKeys {
    const ID = 'id';
    const NAME = 'name';
    const PRICE = 'price';
    const CATEGORY = 'category';
}

$product = [
    ProductKeys::ID => 1,
    ProductKeys::NAME => '产品A',
    ProductKeys::PRICE => 100.00,
    ProductKeys::CATEGORY => '电子'
];

// 4. 数组验证
function validateProductArray($product) {
    $requiredKeys = [ProductKeys::ID, ProductKeys::NAME, ProductKeys::PRICE];
    
    foreach ($requiredKeys as $key) {
        if (!array_key_exists($key, $product)) {
            throw new InvalidArgumentException("缺少必需的键:$key");
        }
    }
    
    if (!is_numeric($product[ProductKeys::PRICE]) || $product[ProductKeys::PRICE] < 0) {
        throw new InvalidArgumentException("价格必须是非负数");
    }
    
    return true;
}

try {
    validateProductArray($product);
    echo "产品数据验证通过\n";
} catch (InvalidArgumentException $e) {
    echo "验证失败:" . $e->getMessage() . "\n";
}

// 5. 数组文档注释
/**
 * 用户信息数组结构
 * 
 * @var array $user {
 *     @type int    $id       用户ID
 *     @type string $name     用户姓名
 *     @type string $email    邮箱地址
 *     @type int    $age      年龄
 *     @type array  $profile  用户资料 {
 *         @type string $avatar   头像URL
 *         @type string $bio      个人简介
 *         @type array  $address  地址信息 {
 *             @type string $city     城市
 *             @type string $district 区域
 *             @type string $street   街道
 *         }
 *     }
 * }
 */
$user = [
    'id' => 1,
    'name' => '张三',
    'email' => 'zhangsan@example.com',
    'age' => 25,
    'profile' => [
        'avatar' => 'https://example.com/avatar.jpg',
        'bio' => '这是个人简介',
        'address' => [
            'city' => '北京',
            'district' => '朝阳区',
            'street' => '建国路1号'
        ]
    ]
];
?>

5.8.2 安全考虑

<?php
// 1. 输入验证
function sanitizeArrayInput($input) {
    if (!is_array($input)) {
        throw new InvalidArgumentException('输入必须是数组');
    }
    
    $sanitized = [];
    foreach ($input as $key => $value) {
        // 验证键名
        if (!is_string($key) && !is_int($key)) {
            continue; // 跳过无效键
        }
        
        // 清理值
        if (is_string($value)) {
            $sanitized[$key] = htmlspecialchars(trim($value), ENT_QUOTES, 'UTF-8');
        } elseif (is_numeric($value)) {
            $sanitized[$key] = $value;
        } elseif (is_array($value)) {
            $sanitized[$key] = sanitizeArrayInput($value); // 递归处理
        }
    }
    
    return $sanitized;
}

// 2. 防止数组注入
function safeArrayMerge($array1, $array2, $allowedKeys = []) {
    if (!empty($allowedKeys)) {
        $array2 = array_intersect_key($array2, array_flip($allowedKeys));
    }
    
    return array_merge($array1, $array2);
}

$userInput = [
    'name' => '张三',
    'email' => 'zhangsan@example.com',
    'admin' => true, // 恶意输入
    'role' => 'admin' // 恶意输入
];

$allowedFields = ['name', 'email'];
$safeData = safeArrayMerge([], $userInput, $allowedFields);
print_r($safeData); // 只包含允许的字段

// 3. 深度限制
function limitArrayDepth($array, $maxDepth = 10, $currentDepth = 0) {
    if ($currentDepth >= $maxDepth) {
        return null; // 超过深度限制
    }
    
    $result = [];
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            $result[$key] = limitArrayDepth($value, $maxDepth, $currentDepth + 1);
        } else {
            $result[$key] = $value;
        }
    }
    
    return $result;
}

// 4. 大小限制
function limitArraySize($array, $maxSize = 1000) {
    if (count($array, COUNT_RECURSIVE) > $maxSize) {
        throw new InvalidArgumentException('数组大小超过限制');
    }
    return $array;
}

// 5. 类型检查
function validateArrayStructure($array, $schema) {
    foreach ($schema as $key => $expectedType) {
        if (!array_key_exists($key, $array)) {
            throw new InvalidArgumentException("缺少必需的键:$key");
        }
        
        $value = $array[$key];
        $actualType = gettype($value);
        
        if (is_array($expectedType)) {
            if (!is_array($value)) {
                throw new InvalidArgumentException("键 $key 应该是数组");
            }
            validateArrayStructure($value, $expectedType);
        } elseif ($actualType !== $expectedType) {
            throw new InvalidArgumentException("键 $key 应该是 $expectedType 类型,实际是 $actualType");
        }
    }
    return true;
}

$schema = [
    'name' => 'string',
    'age' => 'integer',
    'profile' => [
        'email' => 'string',
        'active' => 'boolean'
    ]
];

$testData = [
    'name' => '张三',
    'age' => 25,
    'profile' => [
        'email' => 'zhangsan@example.com',
        'active' => true
    ]
];

try {
    validateArrayStructure($testData, $schema);
    echo "数组结构验证通过\n";
} catch (InvalidArgumentException $e) {
    echo "验证失败:" . $e->getMessage() . "\n";
}
?>

5.9 小结

本章全面介绍了PHP数组的各个方面:

  1. 数组基础:概念、类型、创建方法
  2. 数组操作:访问、修改、遍历
  3. 数组函数:信息函数、操作函数、排序函数、过滤映射函数
  4. 多维数组:创建、操作、实际应用
  5. 性能优化:性能考虑、优化技巧
  6. 最佳实践:编码规范、安全考虑

数组是PHP中最重要的数据结构之一,掌握数组的使用对于PHP开发至关重要。

5.10 实践练习

  1. 基础练习

    • 创建不同类型的数组
    • 实现数组的基本操作
    • 练习数组遍历方法
  2. 函数练习

    • 使用各种数组函数
    • 实现自定义数组操作函数
    • 练习数组排序和过滤
  3. 实际应用练习

    • 实现购物车系统
    • 创建学生成绩管理
    • 构建配置管理系统
  4. 性能优化练习

    • 比较不同操作的性能
    • 优化大数组处理
    • 实现缓存机制

5.11 扩展阅读

  1. PHP数组官方文档
  2. PHP数组函数参考
  3. 数据结构与算法
  4. PHP性能优化指南
  5. 函数式编程思想

下一章预告:在下一章中,我们将学习PHP的字符串处理,包括字符串操作、正则表达式、字符编码等内容。