多维数组

多维数组是指数组中包含其他数组作为其元素的数据结构。在PHP中,你可以创建二维、三维甚至更高维度的数组来组织和存储复杂的数据。多维数组在处理表格数据、配置文件、嵌套数据结构等方面非常有用。

什么是多维数组?

多维数组(Multidimensional Array)是包含一个或多个数组的数组。最常见的多维数组是二维数组,可以想象成表格或矩阵的形式。

// 二维数组示例 - 表格数据
$students = [
    ["张三", 20, "计算机科学"],
    ["李四", 21, "软件工程"],
    ["王五", 19, "信息安全"]
];

// 三维数组示例 - 多个班级的学生
$school = [
    "class1" => [
        ["张三", 20, "计算机科学"],
        ["李四", 21, "软件工程"]
    ],
    "class2" => [
        ["王五", 19, "信息安全"],
        ["赵六", 20, "人工智能"]
    ]
];

创建多维数组

1. 直接创建

// 二维数组 - 产品信息表
$products = [
    ["iPhone 15", "Apple", 5999, "手机"],
    ["MacBook Pro", "Apple", 14999, "笔记本"],
    ["Galaxy S24", "Samsung", 4999, "手机"],
    ["ThinkPad X1", "Lenovo", 12999, "笔记本"]
];

// 三维数组 - 销售数据
$salesData = [
    "2023" => [
        "Q1" => [100000, 120000, 110000],
        "Q2" => [130000, 140000, 125000],
        "Q3" => [135000, 145000, 130000],
        "Q4" => [150000, 160000, 140000]
    ],
    "2024" => [
        "Q1" => [155000, 165000, 150000],
        "Q2" => [160000, 170000, 155000],
        "Q3" => [165000, 175000, 160000],
        "Q4" => [170000, 180000, 165000]
    ]
];

2. 逐步构建

// 创建空的二维数组
$matrix = [];

// 逐行添加数据
for ($i = 0; $i < 3; $i++) {
    $row = [];
    for ($j = 0; $j < 3; $j++) {
        $row[] = $i * 3 + $j + 1;
    }
    $matrix[] = $row;
}
// 结果:[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

// 动态创建用户数据
$users = [];
$userData = [
    ["张三", "zhangsan@example.com", "北京"],
    ["李四", "lisi@example.com", "上海"],
    ["王五", "wangwu@example.com", "广州"]
];

foreach ($userData as $data) {
    $users[] = [
        "name" => $data[0],
        "email" => $data[1],
        "city" => $data[2],
        "profile" => [
            "age" => rand(20, 30),
            "status" => "active",
            "level" => "standard"
        ]
    ];
}

3. 使用函数创建

// 使用array_fill创建二维数组
$grid = array_fill(0, 3, array_fill(0, 4, 0));
// 结果:3x4的零矩阵

// 使用range创建
$multiplicationTable = [];
for ($i = 1; $i <= 9; $i++) {
    $multiplicationTable[] = range($i, $i * 9, $i);
}

// 创建更复杂的三维数组
$categories = [
    "electronics" => ["phones", "laptops", "tablets"],
    "clothing" => ["shirts", "pants", "shoes"],
    "books" => ["fiction", "non-fiction", "textbooks"]
];

$inventory = [];
foreach ($categories as $category => $items) {
    $inventory[$category] = [];
    foreach ($items as $item) {
        $inventory[$category][$item] = [
            "stock" => rand(10, 100),
            "price" => rand(100, 1000),
            "supplier" => "供应商" . rand(1, 5)
        ];
    }
}

访问多维数组

1. 基本访问方式

$students = [
    ["张三", 20, "计算机科学", [85, 92, 78]],
    ["李四", 21, "软件工程", [90, 88, 95]],
    ["王五", 19, "信息安全", [82, 79, 88]]
];

// 访问二维数组元素
echo $students[0][0];  // 输出:张三
echo $students[1][2];  // 输出:软件工程

// 访问三维数组元素
echo $students[0][3][0];  // 输出:85(张三的第一个成绩)

// 修改元素
$students[0][1] = 22;  // 张三年龄改为22
$students[1][3][1] = 91;  // 李四第二个成绩改为91

2. 使用键名的访问

$employees = [
    "dept1" => [
        "manager" => ["name" => "张经理", "salary" => 15000],
        "staff" => [
            ["name" => "李四", "salary" => 8000],
            ["name" => "王五", "salary" => 7500]
        ]
    ],
    "dept2" => [
        "manager" => ["name" => "赵经理", "salary" => 14000],
        "staff" => [
            ["name" => "钱六", "salary" => 8500],
            ["name" => "孙七", "salary" => 7200]
        ]
    ]
];

// 访问嵌套数据
echo $employees["dept1"]["manager"]["name"];     // 输出:张经理
echo $employees["dept1"]["staff"][0]["salary"];   // 输出:8000
echo $employees["dept2"]["staff"][1]["name"];     // 输出:孙七

// 安全访问(检查键是否存在)
$dept3Manager = $employees["dept3"]["manager"]["name"] ?? "未知部门";
echo $dept3Manager;  // 输出:未知部门

3. 动态访问

$config = [
    "database" => [
        "connections" => [
            "mysql" => [
                "host" => "localhost",
                "port" => 3306,
                "database" => "myapp"
            ],
            "postgres" => [
                "host" => "localhost",
                "port" => 5432,
                "database" => "myapp_pg"
            ]
        ]
    ]
];

// 使用变量访问
$connectionType = "mysql";
$host = $config["database"]["connections"][$connectionType]["host"];
echo $host;  // 输出:localhost

// 函数式访问
function getConfigValue($config, $path, $default = null) {
    $keys = explode(".", $path);
    $current = $config;

    foreach ($keys as $key) {
        if (!is_array($current) || !array_key_exists($key, $current)) {
            return $default;
        }
        $current = $current[$key];
    }

    return $current;
}

$dbPort = getConfigValue($config, "database.connections.postgres.port", 3306);
echo $dbPort;  // 输出:5432

遍历多维数组

1. 嵌套foreach循环

$matrix = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12]
];

// 遍历二维数组
echo "=== 矩阵内容 ===\n";
foreach ($matrix as $rowIndex => $row) {
    foreach ($row as $colIndex => $value) {
        echo "[{$rowIndex}][{$colIndex}] = {$value}\t";
    }
    echo "\n";
}

// 计算每行的和
foreach ($matrix as $rowIndex => $row) {
    $rowSum = array_sum($row);
    echo "第 {$rowIndex} 行的和:{$rowSum}\n";
}

2. 遍历复杂的多维数组

$products = [
    "electronics" => [
        "phones" => [
            ["iPhone 15", 5999, 50],
            ["Samsung S24", 4999, 30]
        ],
        "laptops" => [
            ["MacBook Pro", 14999, 20],
            ["ThinkPad X1", 12999, 15]
        ]
    ],
    "clothing" => [
        "shirts" => [
            ["T-Shirt", 99, 100],
            ["Dress Shirt", 199, 50]
        ]
    ]
];

// 遍历并格式化输出
foreach ($products as $category => $categories) {
    echo "分类:{$category}\n";

    foreach ($categories as $subCategory => $items) {
        echo "  子分类:{$subCategory}\n";

        foreach ($items as $item) {
            list($name, $price, $stock) = $item;
            echo "    - {$name}:¥{$price} (库存:{$stock})\n";
        }
    }
    echo "\n";
}

3. 使用递归遍历

$data = [
    "level1" => [
        "level2" => [
            "level3" => "深度值",
            "level3_b" => ["深度数组", "嵌套值"]
        ],
        "level2_b" => "中级值"
    ],
    "level1_b" => "表层值"
];

// 递归遍历函数
function traverseArray($array, $depth = 0) {
    $indent = str_repeat("  ", $depth);

    foreach ($array as $key => $value) {
        if (is_array($value)) {
            echo "{$indent}{$key}:\n";
            traverseArray($value, $depth + 1);
        } else {
            echo "{$indent}{$key}: {$value}\n";
        }
    }
}

// 扁平化数组函数
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";
traverseArray($data);

echo "\n=== 扁平化结果 ===\n";
$flattened = flattenArray($data);
print_r($flattened);

常用操作

1. 数组转换

// 二维数组转一维数组
$students = [
    ["张三", 20, "计算机科学"],
    ["李四", 21, "软件工程"],
    ["王五", 19, "信息安全"]
];

// 提取所有姓名
$names = array_column($students, 0);
// 结果:["张三", "李四", "王五"]

// 使用关联数组
$users = [
    ["id" => 1, "name" => "张三", "email" => "zhangsan@example.com"],
    ["id" => 2, "name" => "李四", "email" => "lisi@example.com"],
    ["id" => 3, "name" => "王五", "email" => "wangwu@example.com"]
];

// 提取name列,以id为键
$userNames = array_column($users, "name", "id");
// 结果:[1 => "张三", 2 => "李四", 3 => "王五"]

// 转置矩阵
function transpose($matrix) {
    return array_map(null, ...$matrix);
}

$matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

$transposed = transpose($matrix);
// 结果:[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

2. 搜索和过滤

$products = [
    ["iPhone 15", "Apple", 5999, "electronics"],
    ["MacBook Pro", "Apple", 14999, "electronics"],
    ["T-Shirt", "H&M", 99, "clothing"],
    ["Jeans", "Levi's", 399, "clothing"]
];

// 搜索特定商品
function searchProduct($products, $searchTerm) {
    $results = [];

    foreach ($products as $product) {
        if (stripos($product[0], $searchTerm) !== false) {
            $results[] = $product;
        }
    }

    return $results;
}

$appleProducts = searchProduct($products, "Apple");
print_r($appleProducts);

// 按分类过滤
function filterByCategory($products, $category) {
    return array_filter($products, function($product) use ($category) {
        return $product[3] === $category;
    });
}

$electronics = array_values(filterByCategory($products, "electronics"));
print_r($electronics);

// 按价格范围过滤
function filterByPriceRange($products, $minPrice, $maxPrice) {
    return array_filter($products, function($product) use ($minPrice, $maxPrice) {
        return $product[2] >= $minPrice && $product[2] <= $maxPrice;
    });
}

$midRange = array_values(filterByPriceRange($products, 100, 1000));
print_r($midRange);

3. 排序和多维排序

$employees = [
    ["张三", "技术部", 8000, 25],
    ["李四", "销售部", 6000, 28],
    ["王五", "技术部", 9000, 30],
    ["赵六", "市场部", 7000, 26]
];

// 按工资排序(降序)
usort($employees, function($a, $b) {
    return $b[2] - $a[2];  // 按第3个元素(工资)降序
});

echo "按工资排序:\n";
foreach ($employees as $emp) {
    echo "{$emp[0]}:{$emp[2]}元\n";
}

// 复杂排序:先按部门,再按工资
usort($employees, function($a, $b) {
    if ($a[1] === $b[1]) {
        return $b[2] - $a[2];  // 同部门按工资降序
    }
    return strcmp($a[1], $b[1]);  // 按部门名称升序
});

echo "\n按部门和工资排序:\n";
foreach ($employees as $emp) {
    echo "{$emp[1]} - {$emp[0]}:{$emp[2]}元\n";
}

// 使用array_multisort排序
$names = array_column($employees, 0);
$salaries = array_column($employees, 2);

// 按工资降序,工资相同按姓名升序
array_multisort($salaries, SORT_DESC, $names, SORT_ASC, $employees);

实际应用示例

1. 学生成绩管理系统

<?php
class GradeManager {
    private $students = [];
    private $subjects = [];

    public function __construct() {
        $this->subjects = ["语文", "数学", "英语", "物理", "化学"];
    }

    // 添加学生
    public function addStudent($name, $class) {
        $studentId = count($this->students) + 1;

        $this->students[$studentId] = [
            "id" => $studentId,
            "name" => $name,
            "class" => $class,
            "grades" => array_fill(0, count($this->subjects), 0),
            "exams" => []
        ];

        return $studentId;
    }

    // 设置成绩
    public function setGrade($studentId, $subjectIndex, $grade) {
        if (isset($this->students[$studentId])) {
            $this->students[$studentId]["grades"][$subjectIndex] = $grade;
            return true;
        }
        return false;
    }

    // 添加考试成绩
    public function addExamResult($studentId, $examName, $grades) {
        if (isset($this->students[$studentId])) {
            $this->students[$studentId]["exams"][] = [
                "exam_name" => $examName,
                "date" => date("Y-m-d"),
                "grades" => $grades,
                "total" => array_sum($grades),
                "average" => array_sum($grades) / count($grades)
            ];
            return true;
        }
        return false;
    }

    // 获取学生总分
    public function getTotalScore($studentId) {
        if (isset($this->students[$studentId])) {
            return array_sum($this->students[$studentId]["grades"]);
        }
        return 0;
    }

    // 获取班级排名
    public function getClassRanking($class = null) {
        $rankings = [];

        foreach ($this->students as $student) {
            if ($class === null || $student["class"] === $class) {
                $totalScore = $this->getTotalScore($student["id"]);
                $rankings[] = [
                    "id" => $student["id"],
                    "name" => $student["name"],
                    "class" => $student["class"],
                    "total_score" => $totalScore,
                    "average_score" => $totalScore / count($this->subjects)
                ];
            }
        }

        // 按总分排序
        usort($rankings, function($a, $b) {
            return $b["total_score"] - $a["total_score"];
        });

        // 添加排名
        foreach ($rankings as $index => &$ranking) {
            $ranking["rank"] = $index + 1;
        }

        return $rankings;
    }

    // 获取科目统计
    public function getSubjectStats() {
        $stats = [];

        foreach ($this->subjects as $subjectIndex => $subject) {
            $scores = array_column($this->students, "grades");
            $subjectScores = array_column($scores, $subjectIndex);

            $stats[$subject] = [
                "highest" => max($subjectScores),
                "lowest" => min($subjectScores),
                "average" => array_sum($subjectScores) / count($subjectScores),
                "pass_rate" => count(array_filter($subjectScores, function($score) {
                    return $score >= 60;
                })) / count($subjectScores) * 100
            ];
        }

        return $stats;
    }

    // 生成成绩单
    public function generateReportCard($studentId) {
        if (!isset($this->students[$studentId])) {
            return null;
        }

        $student = $this->students[$studentId];
        $totalScore = $this->getTotalScore($studentId);
        $averageScore = $totalScore / count($this->subjects);

        return [
            "student_info" => [
                "id" => $student["id"],
                "name" => $student["name"],
                "class" => $student["class"]
            ],
            "subjects" => array_map(function($grade, $subject) {
                return [
                    "name" => $subject,
                    "score" => $grade,
                    "level" => $this->getGradeLevel($grade)
                ];
            }, $student["grades"], $this->subjects),
            "summary" => [
                "total_score" => $totalScore,
                "average_score" => round($averageScore, 1),
                "class_rank" => $this->getStudentRank($studentId),
                "grade_level" => $this->getGradeLevel($averageScore)
            ],
            "exam_history" => $student["exams"]
        ];
    }

    // 获取等级
    private function getGradeLevel($score) {
        if ($score >= 90) return "优秀";
        if ($score >= 80) return "良好";
        if ($score >= 70) return "中等";
        if ($score >= 60) return "及格";
        return "不及格";
    }

    // 获取学生排名
    private function getStudentRank($studentId) {
        $rankings = $this->getClassRanking($this->students[$studentId]["class"]);

        foreach ($rankings as $ranking) {
            if ($ranking["id"] == $studentId) {
                return $ranking["rank"];
            }
        }

        return 0;
    }

    // 显示班级排名
    public function displayClassRanking($class = null) {
        $rankings = $this->getClassRanking($class);
        $title = $class ? "班级 {$class} 排名" : "全校排名";

        echo "=== {$title} ===\n\n";
        printf("%-5s %-10s %-10s %-10s %-10s %-10s\n",
               "排名", "姓名", "班级", "总分", "平均分", "等级");
        echo str_repeat("-", 60) . "\n";

        foreach ($rankings as $ranking) {
            printf("%-5d %-10s %-10s %-10d %-10.1f %-10s\n",
                   $ranking["rank"],
                   $ranking["name"],
                   $ranking["class"],
                   $ranking["total_score"],
                   $ranking["average_score"],
                   $this->getGradeLevel($ranking["average_score"])
            );
        }
    }
}

// 使用示例
$gradeManager = new GradeManager();

// 添加学生
$students = [
    ["张三", "高三1班"],
    ["李四", "高三1班"],
    ["王五", "高三2班"],
    ["赵六", "高三2班"],
    ["钱七", "高三1班"]
];

foreach ($students as [$name, $class]) {
    $gradeManager->addStudent($name, $class);
}

// 设置成绩
$grades = [
    1 => [85, 92, 88, 90, 87],
    2 => [78, 95, 82, 88, 91],
    3 => [92, 88, 90, 85, 89],
    4 => [80, 85, 78, 82, 80],
    5 => [88, 91, 85, 89, 86]
];

foreach ($grades as $studentId => $studentGrades) {
    foreach ($studentGrades as $subjectIndex => $grade) {
        $gradeManager->setGrade($studentId, $subjectIndex, $grade);
    }
}

// 添加考试成绩
$gradeManager->addExamResult(1, "期中考试", [82, 89, 85, 88, 84]);
$gradeManager->addExamResult(1, "期末考试", [87, 94, 90, 91, 88]);

// 显示排名
$gradeManager->displayClassRanking();
echo "\n";

// 显示特定班级排名
$gradeManager->displayClassRanking("高三1班");
echo "\n";

// 显示科目统计
$subjectStats = $gradeManager->getSubjectStats();
echo "=== 科目统计 ===\n";
foreach ($subjectStats as $subject => $stats) {
    echo "{$subject}:\n";
    echo "  最高分:{$stats['highest']}\n";
    echo "  最低分:{$stats['lowest']}\n";
    echo "  平均分:{$stats['average']:.1f}\n";
    echo "  及格率:{$stats['pass_rate']:.1f}%\n\n";
}

// 生成成绩单
$reportCard = $gradeManager->generateReportCard(1);
echo "=== 学生成绩单 ===\n";
echo "学生:{$reportCard['student_info']['name']} ({$reportCard['student_info']['class']})\n\n";

echo "各科成绩:\n";
foreach ($reportCard['subjects'] as $subject) {
    echo "  {$subject['name']}:{$subject['score']}分 ({$subject['level']})\n";
}

echo "\n总分:{$reportCard['summary']['total_score']}分\n";
echo "平均分:{$reportCard['summary']['average_score']}分\n";
echo "班级排名:第{$reportCard['summary']['class_rank']}名\n";
echo "综合等级:{$reportCard['summary']['grade_level']}\n";

if (!empty($reportCard['exam_history'])) {
    echo "\n考试历史:\n";
    foreach ($reportCard['exam_history'] as $exam) {
        echo "  {$exam['exam_name']} ({$exam['date']}):";
        echo "{$exam['total']}分 (平均{$exam['average']:.1f}分)\n";
    }
}
?>

2. 电商库存管理系统

<?php
class InventoryManager {
    private $warehouses = [];
    private $products = [];

    public function __construct() {
        // 初始化仓库
        $this->warehouses = [
            "WH001" => ["name" => "北京仓库", "location" => "北京"],
            "WH002" => ["name" => "上海仓库", "location" => "上海"],
            "WH003" => ["name" => "广州仓库", "location" => "广州"]
        ];

        // 初始化库存数据
        foreach ($this->warehouses as $warehouseId => $warehouse) {
            $this->products[$warehouseId] = [];
        }
    }

    // 添加产品到仓库
    public function addProduct($warehouseId, $productId, $productName, $quantity, $price) {
        if (!isset($this->products[$warehouseId])) {
            throw new Exception("仓库不存在");
        }

        if (isset($this->products[$warehouseId][$productId])) {
            // 产品已存在,更新数量
            $this->products[$warehouseId][$productId]["quantity"] += $quantity;
            // 更新平均价格
            $currentValue = $this->products[$warehouseId][$productId]["quantity"] *
                           $this->products[$warehouseId][$productId]["price"];
            $newValue = $currentValue + ($quantity * $price);
            $newQuantity = $this->products[$warehouseId][$productId]["quantity"] + $quantity;
            $this->products[$warehouseId][$productId]["price"] = $newValue / $newQuantity;
        } else {
            // 新产品
            $this->products[$warehouseId][$productId] = [
                "name" => $productName,
                "quantity" => $quantity,
                "price" => $price,
                "total_value" => $quantity * $price,
                "last_updated" => date("Y-m-d H:i:s")
            ];
        }

        return true;
    }

    // 转移库存
    public function transferStock($fromWarehouse, $toWarehouse, $productId, $quantity) {
        if (!isset($this->products[$fromWarehouse][$productId])) {
            throw new Exception("源仓库没有该产品");
        }

        if ($this->products[$fromWarehouse][$productId]["quantity"] < $quantity) {
            throw new Exception("库存不足");
        }

        // 从源仓库移除
        $this->products[$fromWarehouse][$productId]["quantity"] -= $quantity;
        $this->products[$fromWarehouse][$productId]["total_value"] -=
            $quantity * $this->products[$fromWarehouse][$productId]["price"];
        $this->products[$fromWarehouse][$productId]["last_updated"] = date("Y-m-d H:i:s");

        // 添加到目标仓库
        $this->addProduct(
            $toWarehouse,
            $productId,
            $this->products[$fromWarehouse][$productId]["name"],
            $quantity,
            $this->products[$fromWarehouse][$productId]["price"]
        );

        return true;
    }

    // 获取产品总库存
    public function getTotalStock($productId) {
        $total = 0;
        $totalValue = 0;
        $warehouses = [];

        foreach ($this->products as $warehouseId => $products) {
            if (isset($products[$productId])) {
                $total += $products[$productId]["quantity"];
                $totalValue += $products[$productId]["total_value"];
                $warehouses[] = [
                    "warehouse_id" => $warehouseId,
                    "warehouse_name" => $this->warehouses[$warehouseId]["name"],
                    "quantity" => $products[$productId]["quantity"]
                ];
            }
        }

        return [
            "product_id" => $productId,
            "total_quantity" => $total,
            "total_value" => $totalValue,
            "average_price" => $total > 0 ? $totalValue / $total : 0,
            "distribution" => $warehouses
        ];
    }

    // 获取仓库库存汇总
    public function getWarehouseSummary($warehouseId) {
        if (!isset($this->products[$warehouseId])) {
            return null;
        }

        $totalProducts = count($this->products[$warehouseId]);
        $totalQuantity = 0;
        $totalValue = 0;

        foreach ($this->products[$warehouseId] as $product) {
            $totalQuantity += $product["quantity"];
            $totalValue += $product["total_value"];
        }

        return [
            "warehouse_id" => $warehouseId,
            "warehouse_name" => $this->warehouses[$warehouseId]["name"],
            "location" => $this->warehouses[$warehouseId]["location"],
            "product_count" => $totalProducts,
            "total_quantity" => $totalQuantity,
            "total_value" => $totalValue
        ];
    }

    // 获取库存预警
    public function getLowStockAlerts($threshold = 10) {
        $alerts = [];

        foreach ($this->products as $warehouseId => $products) {
            foreach ($products as $productId => $product) {
                if ($product["quantity"] <= $threshold) {
                    $alerts[] = [
                        "warehouse_id" => $warehouseId,
                        "warehouse_name" => $this->warehouses[$warehouseId]["name"],
                        "product_id" => $productId,
                        "product_name" => $product["name"],
                        "current_quantity" => $product["quantity"],
                        "threshold" => $threshold
                    ];
                }
            }
        }

        return $alerts;
    }

    // 生成库存报告
    public function generateInventoryReport() {
        $report = [
            "generated_at" => date("Y-m-d H:i:s"),
            "warehouses" => [],
            "summary" => [
                "total_warehouses" => count($this->warehouses),
                "total_products" => 0,
                "total_quantity" => 0,
                "total_value" => 0
            ]
        ];

        foreach ($this->warehouses as $warehouseId => $warehouse) {
            $summary = $this->getWarehouseSummary($warehouseId);
            if ($summary) {
                $report["warehouses"][] = $summary;
                $report["summary"]["total_products"] += $summary["product_count"];
                $report["summary"]["total_quantity"] += $summary["total_quantity"];
                $report["summary"]["total_value"] += $summary["total_value"];
            }
        }

        return $report;
    }

    // 显示仓库详情
    public function displayWarehouseDetails($warehouseId) {
        if (!isset($this->products[$warehouseId])) {
            echo "仓库不存在\n";
            return;
        }

        $warehouse = $this->warehouses[$warehouseId];
        echo "=== {$warehouse['name']} ({$warehouseId}) ===\n";
        echo "位置:{$warehouse['location']}\n\n";

        if (empty($this->products[$warehouseId])) {
            echo "仓库为空\n";
            return;
        }

        printf("%-15s %-20s %-10s %-10s %-15s\n",
               "产品ID", "产品名称", "数量", "单价", "总价值");
        echo str_repeat("-", 70) . "\n";

        foreach ($this->products[$warehouseId] as $productId => $product) {
            printf("%-15s %-20s %-10d %-10.2f %-15.2f\n",
                   $productId,
                   $product["name"],
                   $product["quantity"],
                   $product["price"],
                   $product["total_value"]
            );
        }

        $summary = $this->getWarehouseSummary($warehouseId);
        echo "\n仓库汇总:\n";
        echo "产品种类:{$summary['product_count']} 种\n";
        echo "总数量:{$summary['total_quantity']} 件\n";
        echo "总价值:¥{$summary['total_value']:.2f}\n";
    }

    // 显示产品分布
    public function displayProductDistribution($productId) {
        $distribution = $this->getTotalStock($productId);

        echo "=== 产品库存分布 ===\n";
        echo "产品ID:{$distribution['product_id']}\n";
        echo "总库存:{$distribution['total_quantity']} 件\n";
        echo "总价值:¥{$distribution['total_value']:.2f}\n";
        echo "平均价格:¥{$distribution['average_price']:.2f}\n\n";

        echo "各仓库分布:\n";
        foreach ($distribution['distribution'] as $warehouse) {
            echo "- {$warehouse['warehouse_name']}:{$warehouse['quantity']} 件\n";
        }
    }
}

// 使用示例
$inventory = new InventoryManager();

// 添加产品到不同仓库
$inventory->addProduct("WH001", "P001", "iPhone 15", 50, 5999);
$inventory->addProduct("WH001", "P002", "MacBook Pro", 20, 14999);
$inventory->addProduct("WH002", "P001", "iPhone 15", 30, 5999);
$inventory->addProduct("WH002", "P003", "AirPods", 100, 1999);
$inventory->addProduct("WH003", "P002", "MacBook Pro", 15, 14999);
$inventory->addProduct("WH003", "P004", "iPad", 40, 3999);

// 显示各仓库详情
foreach (["WH001", "WH002", "WH003"] as $warehouseId) {
    $inventory->displayWarehouseDetails($warehouseId);
    echo "\n";
}

// 显示产品分布
$inventory->displayProductDistribution("P001");
echo "\n";

// 库存转移
try {
    $inventory->transferStock("WH001", "WH002", "P001", 10);
    echo "成功转移10个iPhone 15从北京仓库到上海仓库\n\n";

    $inventory->displayProductDistribution("P001");
} catch (Exception $e) {
    echo "转移失败:" . $e->getMessage() . "\n";
}

// 库存预警
$alerts = $inventory->getLowStockAlerts(25);
if (!empty($alerts)) {
    echo "=== 库存预警 ===\n";
    foreach ($alerts as $alert) {
        echo "仓库:{$alert['warehouse_name']}\n";
        echo "产品:{$alert['product_name']} ({$alert['product_id']})\n";
        echo "当前库存:{$alert['current_quantity']} (阈值:{$alert['threshold']})\n\n";
    }
} else {
    echo "无库存预警\n";
}

// 生成完整报告
$report = $inventory->generateInventoryReport();
echo "=== 库存总报告 ===\n";
echo "生成时间:{$report['generated_at']}\n";
echo "总仓库数:{$report['summary']['total_warehouses']}\n";
echo "总产品种类:{$report['summary']['total_products']}\n";
echo "总库存量:{$report['summary']['total_quantity']} 件\n";
echo "总库存价值:¥{$report['summary']['total_value']:.2f}\n";
?>

3. 数据分析工具

<?php
class DataAnalyzer {
    private $data = [];

    // 加载数据
    public function loadData($data) {
        $this->data = $data;
    }

    // 从CSV文件加载数据
    public function loadFromCSV($filename) {
        if (!file_exists($filename)) {
            throw new Exception("文件不存在");
        }

        $this->data = [];
        $handle = fopen($filename, 'r');

        // 读取表头
        $headers = fgetcsv($handle);

        // 读取数据行
        while (($row = fgetcsv($handle)) !== false) {
            $this->data[] = array_combine($headers, $row);
        }

        fclose($handle);
    }

    // 获取数据概览
    public function getDataOverview() {
        if (empty($this->data)) {
            return null;
        }

        $overview = [
            "total_rows" => count($this->data),
            "columns" => array_keys($this->data[0]),
            "column_info" => []
        ];

        foreach ($overview["columns"] as $column) {
            $values = array_column($this->data, $column);
            $numericValues = array_filter($values, function($value) {
                return is_numeric($value);
            });

            $overview["column_info"][$column] = [
                "type" => count($numericValues) > 0 ? "numeric" : "text",
                "null_count" => count(array_filter($values, function($value) {
                    return $value === null || $value === '';
                })),
                "unique_values" => count(array_unique($values))
            ];

            if ($overview["column_info"][$column]["type"] === "numeric") {
                $numericValues = array_map('floatval', $numericValues);
                $overview["column_info"][$column]["min"] = min($numericValues);
                $overview["column_info"][$column]["max"] = max($numericValues);
                $overview["column_info"][$column]["average"] = array_sum($numericValues) / count($numericValues);
            }
        }

        return $overview;
    }

    // 按列分组统计
    public function groupBy($column, $valueColumn = null) {
        if (empty($this->data)) {
            return [];
        }

        $groups = [];

        foreach ($this->data as $row) {
            $key = $row[$column] ?? 'Unknown';

            if (!isset($groups[$key])) {
                $groups[$key] = [
                    "count" => 0,
                    "values" => [],
                    "rows" => []
                ];
            }

            $groups[$key]["count"]++;
            $groups[$key]["rows"][] = $row;

            if ($valueColumn && isset($row[$valueColumn]) && is_numeric($row[$valueColumn])) {
                $groups[$key]["values"][] = floatval($row[$valueColumn]);
            }
        }

        // 计算统计信息
        foreach ($groups as $key => &$group) {
            if (!empty($group["values"])) {
                $group["sum"] = array_sum($group["values"]);
                $group["average"] = $group["sum"] / count($group["values"]);
                $group["min"] = min($group["values"]);
                $group["max"] = max($group["values"]);
            }
        }

        return $groups;
    }

    // 数据透视表
    public function pivotTable($indexColumn, $columnColumn, $valueColumn, $aggregation = 'sum') {
        if (empty($this->data)) {
            return [];
        }

        $pivot = [];
        $columnValues = [];

        // 收集所有列值
        foreach ($this->data as $row) {
            $colValue = $row[$columnColumn] ?? 'Unknown';
            if (!in_array($colValue, $columnValues)) {
                $columnValues[] = $colValue;
            }
        }

        // 初始化透视表
        foreach ($this->data as $row) {
            $indexValue = $row[$indexColumn] ?? 'Unknown';

            if (!isset($pivot[$indexValue])) {
                $pivot[$indexValue] = array_fill_keys($columnValues, 0);
            }

            $colValue = $row[$columnColumn] ?? 'Unknown';
            $value = isset($row[$valueColumn]) && is_numeric($row[$valueColumn])
                    ? floatval($row[$valueColumn]) : 0;

            switch ($aggregation) {
                case 'sum':
                    $pivot[$indexValue][$colValue] += $value;
                    break;
                case 'count':
                    $pivot[$indexValue][$colValue]++;
                    break;
                case 'average':
                    // 平均值需要特殊处理
                    if (!isset($pivot[$indexValue][$colValue . '_sum'])) {
                        $pivot[$indexValue][$colValue . '_sum'] = 0;
                        $pivot[$indexValue][$colValue . '_count'] = 0;
                    }
                    $pivot[$indexValue][$colValue . '_sum'] += $value;
                    $pivot[$indexValue][$colValue . '_count']++;
                    $pivot[$indexValue][$colValue] = $pivot[$indexValue][$colValue . '_sum'] /
                                                    $pivot[$indexValue][$colValue . '_count'];
                    break;
            }
        }

        // 清理临时数据
        if ($aggregation === 'average') {
            foreach ($pivot as &$row) {
                foreach ($row as $key => $value) {
                    if (strpos($key, '_sum') !== false || strpos($key, '_count') !== false) {
                        unset($row[$key]);
                    }
                }
            }
        }

        return $pivot;
    }

    // 数据筛选
    public function filter($conditions) {
        return array_filter($this->data, function($row) use ($conditions) {
            foreach ($conditions as $column => $condition) {
                $value = $row[$column] ?? null;

                if (is_array($condition)) {
                    // 范围条件 ['min' => 10, 'max' => 100]
                    if (isset($condition['min']) && $value < $condition['min']) {
                        return false;
                    }
                    if (isset($condition['max']) && $value > $condition['max']) {
                        return false;
                    }
                    if (isset($condition['in']) && !in_array($value, $condition['in'])) {
                        return false;
                    }
                } else {
                    // 精确匹配
                    if ($value != $condition) {
                        return false;
                    }
                }
            }
            return true;
        });
    }

    // 数据排序
    public function sort($columns, $order = 'asc') {
        $sortedData = $this->data;

        usort($sortedData, function($a, $b) use ($columns, $order) {
            foreach ($columns as $column) {
                $aValue = $a[$column] ?? 0;
                $bValue = $b[$column] ?? 0;

                if ($aValue != $bValue) {
                    $result = $aValue <=> $bValue;
                    return $order === 'desc' ? -$result : $result;
                }
            }
            return 0;
        });

        return $sortedData;
    }

    // 显示数据表格
    public function displayTable($data = null, $limit = 10) {
        $displayData = $data ?? $this->data;

        if (empty($displayData)) {
            echo "没有数据可显示\n";
            return;
        }

        $columns = array_keys($displayData[0]);
        $displayCount = min($limit, count($displayData));

        // 计算列宽
        $columnWidths = [];
        foreach ($columns as $column) {
            $columnWidths[$column] = strlen($column);
        }

        for ($i = 0; $i < $displayCount; $i++) {
            foreach ($columns as $column) {
                $value = (string)($displayData[$i][$column] ?? '');
                $columnWidths[$column] = max($columnWidths[$column], strlen($value));
            }
        }

        // 显示表头
        foreach ($columns as $column) {
            printf("%-{$columnWidths[$column]}s  ", $column);
        }
        echo "\n";

        // 显示分隔线
        foreach ($columns as $column) {
            echo str_repeat("-", $columnWidths[$column]) . "  ";
        }
        echo "\n";

        // 显示数据行
        for ($i = 0; $i < $displayCount; $i++) {
            foreach ($columns as $column) {
                $value = (string)($displayData[$i][$column] ?? '');
                printf("%-{$columnWidths[$column]}s  ", $value);
            }
            echo "\n";
        }

        if ($displayCount < count($displayData)) {
            echo "\n... 显示前 {$displayCount} 行,共 " . count($displayData) . " 行\n";
        }
    }
}

// 使用示例
$analyzer = new DataAnalyzer();

// 创建示例销售数据
$salesData = [
    ["date" => "2023-01-01", "region" => "北京", "product" => "iPhone", "sales" => 120, "revenue" => 719880],
    ["date" => "2023-01-01", "region" => "上海", "product" => "iPhone", "sales" => 98, "revenue" => 587902],
    ["date" => "2023-01-01", "region" => "广州", "product" => "MacBook", "sales" => 45, "revenue" => 674955],
    ["date" => "2023-01-02", "region" => "北京", "product" => "MacBook", "sales" => 38, "revenue" => 569962],
    ["date" => "2023-01-02", "region" => "上海", "product" => "iPad", "sales" => 67, "revenue" => 267933],
    ["date" => "2023-01-02", "region" => "广州", "product" => "iPhone", "sales" => 85, "revenue" => 509915],
    ["date" => "2023-01-03", "region" => "北京", "product" => "iPad", "sales" => 52, "revenue" => 207948],
    ["date" => "2023-01-03", "region" => "上海", "product" => "MacBook", "sales" => 42, "revenue" => 629958],
    ["date" => "2023-01-03", "region" => "广州", "product" => "iPad", "sales" => 61, "revenue" => 243939]
];

$analyzer->loadData($salesData);

echo "=== 数据概览 ===\n";
$overview = $analyzer->getDataOverview();
echo "总行数:{$overview['total_rows']}\n";
echo "列数:" . count($overview['columns']) . "\n";
echo "列名:" . implode(", ", $overview['columns']) . "\n\n";

echo "=== 列信息 ===\n";
foreach ($overview['column_info'] as $column => $info) {
    echo "{$column}:\n";
    echo "  类型:{$info['type']}\n";
    echo "  空值数:{$info['null_count']}\n";
    echo "  唯一值数:{$info['unique_values']}\n";

    if ($info['type'] === 'numeric') {
        echo "  最小值:{$info['min']}\n";
        echo "  最大值:{$info['max']}\n";
        echo "  平均值:{$info['average']:.2f}\n";
    }
    echo "\n";
}

echo "=== 原始数据表格 ===\n";
$analyzer->displayTable(null, 5);

echo "\n=== 按地区分组统计 ===\n";
$regionGroups = $analyzer->groupBy("region", "revenue");
foreach ($regionGroups as $region => $group) {
    echo "{$region}:\n";
    echo "  记录数:{$group['count']}\n";
    echo "  总收入:¥{$group['sum']:,.0f}\n";
    echo "  平均收入:¥{$group['average']:,.0f}\n";
    echo "  最高收入:¥{$group['max']:,.0f}\n";
    echo "  最低收入:¥{$group['min']:,.0f}\n\n";
}

echo "=== 产品销售透视表(按地区) ===\n";
$pivotTable = $analyzer->pivotTable("region", "product", "sales", "sum");

// 显示透视表
$products = array_unique(array_column($salesData, 'product'));
$regions = array_unique(array_column($salesData, 'region'));

printf("%-10s", "地区\\产品");
foreach ($products as $product) {
    printf("%-10s", $product);
}
echo "\n";

foreach ($regions as $region) {
    printf("%-10s", $region);
    foreach ($products as $product) {
        $sales = $pivotTable[$region][$product] ?? 0;
        printf("%-10d", $sales);
    }
    echo "\n";
}

echo "\n=== 筛选数据(收入大于500000) ===\n";
$filtered = $analyzer->filter(["revenue" => ["min" => 500000]]);
$analyzer->displayTable($filtered);

echo "\n=== 按收入排序 ===\n";
$sorted = $analyzer->sort(["revenue"], "desc");
$analyzer->displayTable($sorted, 5);
?>

常见错误和解决方案

1. 数组维度错误

// 错误:试图访问不存在的维度
$data = [[1, 2], [3, 4]];
echo $data[0][2];  // Notice: Undefined offset

// 正确做法:检查数组维度
function getNestedValue($array, $path) {
    $current = $array;
    foreach ($path as $key) {
        if (!is_array($current) || !array_key_exists($key, $current)) {
            return null;
        }
        $current = $current[$key];
    }
    return $current;
}

$value = getNestedValue($data, [0, 1]);  // 安全访问

2. 引用传递问题

// 错误:意外修改原数组
$original = [[1, 2], [3, 4]];
$copy = $original;
$copy[0][0] = 99;  // $original也会被修改

// 正确做法:深拷贝
$deepCopy = json_decode(json_encode($original), true);
$deepCopy[0][0] = 99;  // 只影响副本

3. 内存使用问题

// 不好的做法:创建过大的数组
$hugeArray = [];
for ($i = 0; $i < 1000000; $i++) {
    $hugeArray[$i] = range(0, 100);  // 可能导致内存不足
}

// 好的做法:使用生成器或分批处理
function processLargeData($count) {
    for ($i = 0; $i < $count; $i++) {
        yield range($i, $i + 100);
    }
}

foreach (processLargeData(1000000) as $batch) {
    // 分批处理数据
}

性能优化建议

1. 选择合适的数据结构

// 对于频繁查找的操作,使用关联数组比多维数组更高效
// 不好的做法
$users = [
    [1, "张三", "zhangsan@example.com"],
    [2, "李四", "lisi@example.com"]
];

// 好的做法
$users = [
    1 => ["name" => "张三", "email" => "zhangsan@example.com"],
    2 => ["name" => "李四", "email" => "lisi@example.com"]
];

// 查找时O(1)时间复杂度
$user = $users[1] ?? null;

2. 避免深层嵌套

// 不好的做法:过深的嵌套
$config["database"]["connections"]["mysql"]["settings"]["timeout"] = 30;

// 好的做法:适当的扁平化
$config["mysql_timeout"] = 30;
// 或者使用配置类来管理

3. 使用内置函数

// 不好的做法:手动循环
$totals = [];
foreach ($data as $row) {
    $category = $row['category'];
    if (!isset($totals[$category])) {
        $totals[$category] = 0;
    }
    $totals[$category] += $row['amount'];
}

// 好的做法:使用内置函数
$totals = array_reduce($data, function($carry, $item) {
    $carry[$item['category']] = ($carry[$item['category']] ?? 0) + $item['amount'];
    return $carry;
}, []);

练习题

基础练习

  1. 创建和访问多维数组

    // 创建一个3x3的乘法表
    // 访问特定行和列的值
    // 计算对角线元素的和
    
  2. 二维数组操作

    // 创建学生成绩表
    // 计算每个学生的总分和平均分
    // 找出每科的最高分
    

进阶练习

  1. 矩阵操作

    // 实现矩阵加法和乘法
    // 计算矩阵的转置
    // 实现矩阵的行列式计算
    
  2. 数据透视

    // 将销售数据转换为透视表
    // 按多个维度分组统计
    // 实现动态的透视表生成
    

实战练习

  1. 简单的电子表格

    // 使用多维数组实现电子表格
    // 支持基本的单元格操作
    // 实现行和列的计算功能
    
  2. 游戏地图编辑器

    // 使用二维数组表示游戏地图
    // 实现地图的加载、保存和编辑
    // 支持图层和对象放置
    

总结

多维数组是PHP中处理复杂数据结构的重要工具。通过本节的学习,你应该:

  1. 理解多维数组的概念和应用场景
  2. 掌握创建、访问和修改多维数组的方法
  3. 熟练遍历和操作多维数组的技巧
  4. 了解多维数组在实际项目中的应用
  5. 能够优化多维数组的性能和内存使用

多维数组是数组学习的进阶内容,掌握好它将让你能够处理更加复杂和层次化的数据结构,为开发复杂的PHP应用打下坚实基础。

接下来,我们将学习常用的数组函数,这将进一步提升我们处理数组的能力。