<返回目录     Powered by claud/xia兄

第6课: 数组操作与处理

数组基础

数组是PHP中最重要的数据结构,可以存储多个值。PHP支持索引数组和关联数组。

创建索引数组

<?php
// 方式1:短数组语法(推荐)
$fruits = ["苹果", "香蕉", "橙子"];

// 方式2:array()函数
$colors = array("红色", "绿色", "蓝色");

// 方式3:逐个赋值
$numbers = [];
$numbers[0] = 10;
$numbers[1] = 20;
$numbers[2] = 30;

// 自动索引
$items = [];
$items[] = "第一项";  // 索引0
$items[] = "第二项";  // 索引1
?>

创建关联数组

<?php
// 使用键值对
$person = [
    "name" => "张三",
    "age" => 25,
    "city" => "北京",
    "email" => "zhang@example.com"
];

// 嵌套数组
$user = [
    "id" => 1,
    "info" => [
        "name" => "李四",
        "age" => 30
    ],
    "tags" => ["PHP", "MySQL", "JavaScript"]
];
?>

访问数组元素

<?php
$fruits = ["苹果", "香蕉", "橙子"];
echo $fruits[0];  // 苹果
echo $fruits[2];  // 橙子

$person = ["name" => "张三", "age" => 25];
echo $person["name"];  // 张三
echo $person["age"];   // 25

// 访问嵌套数组
$user = [
    "info" => ["name" => "王五", "age" => 28]
];
echo $user["info"]["name"];  // 王五

// 使用变量作为键
$key = "name";
echo $person[$key];  // 张三
?>

修改和删除数组元素

<?php
$fruits = ["苹果", "香蕉", "橙子"];

// 修改元素
$fruits[1] = "草莓";  // ["苹果", "草莓", "橙子"]

// 添加元素
$fruits[3] = "葡萄";
$fruits[] = "西瓜";  // 自动添加到末尾

// 删除元素
unset($fruits[1]);  // 删除索引1的元素
unset($fruits);     // 删除整个数组

// 清空数组
$fruits = [];
?>

数组操作函数

添加和删除元素

<?php
$stack = [1, 2, 3];

// 末尾操作
array_push($stack, 4, 5);  // [1, 2, 3, 4, 5]
$last = array_pop($stack);  // 移除并返回5

// 开头操作
array_unshift($stack, 0);   // [0, 1, 2, 3, 4]
$first = array_shift($stack); // 移除并返回0

// 删除指定位置
array_splice($stack, 1, 2);  // 从索引1删除2个元素
?>

数组合并和分割

<?php
$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];

// 合并数组
$merged = array_merge($arr1, $arr2);  // [1, 2, 3, 4, 5, 6]
$combined = $arr1 + $arr2;  // 使用+运算符

// 分割数组
$chunks = array_chunk($merged, 2);  // [[1, 2], [3, 4], [5, 6]]

// 提取部分数组
$slice = array_slice($merged, 2, 3);  // [3, 4, 5]
?>

数组搜索和检查

<?php
$fruits = ["苹果", "香蕉", "橙子", "香蕉"];

// 检查元素是否存在
in_array("香蕉", $fruits);  // true
in_array("葡萄", $fruits);  // false

// 查找元素位置
$pos = array_search("橙子", $fruits);  // 2
$pos = array_search("葡萄", $fruits);  // false

// 检查键是否存在
$person = ["name" => "张三", "age" => 25];
array_key_exists("name", $person);  // true
isset($person["name"]);  // true

// 获取所有键和值
$keys = array_keys($person);    // ["name", "age"]
$values = array_values($person); // ["张三", 25]
?>

数组排序

索引数组排序

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

// 升序排序
sort($numbers);  // [1, 1, 2, 3, 4, 5, 6, 9]

// 降序排序
rsort($numbers);  // [9, 6, 5, 4, 3, 2, 1, 1]

// 保持键值关联的排序
$data = [2 => "b", 0 => "a", 1 => "c"];
asort($data);  // 按值排序,保持键
arsort($data); // 按值降序,保持键
?>

关联数组排序

<?php
$person = [
    "name" => "张三",
    "age" => 25,
    "city" => "北京"
];

// 按值排序
asort($person);   // 升序
arsort($person);  // 降序

// 按键排序
ksort($person);   // 升序
krsort($person);  // 降序

// 自定义排序
$users = [
    ["name" => "张三", "age" => 25],
    ["name" => "李四", "age" => 30],
    ["name" => "王五", "age" => 20]
];

usort($users, function($a, $b) {
    return $a["age"] - $b["age"];  // 按年龄排序
});
?>

数组遍历

foreach循环

<?php
$fruits = ["苹果", "香蕉", "橙子"];

// 遍历值
foreach ($fruits as $fruit) {
    echo $fruit . "\n";
}

// 遍历键和值
foreach ($fruits as $index => $fruit) {
    echo "$index: $fruit\n";
}

// 关联数组遍历
$person = ["name" => "张三", "age" => 25];
foreach ($person as $key => $value) {
    echo "$key = $value\n";
}
?>

数组指针操作

<?php
$arr = ["a", "b", "c", "d"];

current($arr);  // "a" - 当前元素
next($arr);     // "b" - 移动到下一个
prev($arr);     // "a" - 移动到上一个
end($arr);      // "d" - 移动到最后
reset($arr);    // "a" - 重置到开头
key($arr);      // 0 - 当前键
?>

数组过滤和映射

array_filter - 过滤数组

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

// 过滤偶数
$even = array_filter($numbers, function($n) {
    return $n % 2 == 0;
});
// 结果: [2, 4, 6, 8, 10]

// 过滤空值
$data = ["", "hello", null, "world", 0, false];
$filtered = array_filter($data);  // ["hello", "world"]
?>

array_map - 映射数组

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

// 每个元素乘以2
$doubled = array_map(function($n) {
    return $n * 2;
}, $numbers);
// 结果: [2, 4, 6, 8, 10]

// 多个数组映射
$a = [1, 2, 3];
$b = [10, 20, 30];
$result = array_map(function($x, $y) {
    return $x + $y;
}, $a, $b);
// 结果: [11, 22, 33]
?>

array_reduce - 归约数组

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

// 求和
$sum = array_reduce($numbers, function($carry, $item) {
    return $carry + $item;
}, 0);
// 结果: 15

// 求积
$product = array_reduce($numbers, function($carry, $item) {
    return $carry * $item;
}, 1);
// 结果: 120
?>

多维数组

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

echo $matrix[1][2];  // 6

// 学生成绩表
$students = [
    [
        "name" => "张三",
        "scores" => ["数学" => 90, "英语" => 85]
    ],
    [
        "name" => "李四",
        "scores" => ["数学" => 88, "英语" => 92]
    ]
];

echo $students[0]["scores"]["数学"];  // 90

// 遍历多维数组
foreach ($students as $student) {
    echo $student["name"] . ":\n";
    foreach ($student["scores"] as $subject => $score) {
        echo "  $subject: $score\n";
    }
}
?>

实际应用场景

电商购物车完整实现

<?php
/**
 * 电商购物车完整实现
 * 功能:添加商品、更新数量、删除商品、计算总价、优惠折扣、保存到会话
 */

class ShoppingCart {
    private $items = [];
    private $discount = 0;
    
    /**
     * 添加商品到购物车
     * @param array $product 商品信息
     * @return void
     */
    public function addProduct($product) {
        // 验证商品数据
        if (!isset($product['id'], $product['name'], $product['price'], $product['quantity'])) {
            throw new InvalidArgumentException('商品信息不完整');
        }
        
        // 检查商品是否已存在
        foreach ($this->items as &$item) {
            if ($item['id'] == $product['id']) {
                $item['quantity'] += $product['quantity'];
                $this->updateSubtotal($item);
                return;
            }
        }
        
        // 添加新商品
        $product['subtotal'] = $product['price'] * $product['quantity'];
        $this->items[] = $product;
    }
    
    /**
     * 更新商品数量
     * @param int $productId 商品ID
     * @param int $quantity 新数量
     * @return void
     */
    public function updateQuantity($productId, $quantity) {
        $quantity = max(1, (int)$quantity);
        
        foreach ($this->items as &$item) {
            if ($item['id'] == $productId) {
                $item['quantity'] = $quantity;
                $this->updateSubtotal($item);
                return;
            }
        }
        
        throw new InvalidArgumentException('商品不存在');
    }
    
    /**
     * 删除商品
     * @param int $productId 商品ID
     * @return void
     */
    public function removeProduct($productId) {
        foreach ($this->items as $key => $item) {
            if ($item['id'] == $productId) {
                unset($this->items[$key]);
                $this->items = array_values($this->items);
                return;
            }
        }
        
        throw new InvalidArgumentException('商品不存在');
    }
    
    /**
     * 清空购物车
     * @return void
     */
    public function clear() {
        $this->items = [];
        $this->discount = 0;
    }
    
    /**
     * 设置折扣
     * @param float $discount 折扣金额或百分比
     * @param bool $isPercentage 是否为百分比
     * @return void
     */
    public function setDiscount($discount, $isPercentage = false) {
        if ($isPercentage) {
            $total = $this->getSubtotal();
            $this->discount = $total * ($discount / 100);
        } else {
            $this->discount = $discount;
        }
        
        $this->discount = max(0, $this->discount);
    }
    
    /**
     * 获取商品数量
     * @return int
     */
    public function getCount() {
        return array_sum(array_column($this->items, 'quantity'));
    }
    
    /**
     * 获取商品种类数
     * @return int
     */
    public function getProductCount() {
        return count($this->items);
    }
    
    /**
     * 获取商品列表
     * @return array
     */
    public function getItems() {
        return $this->items;
    }
    
    /**
     * 获取小计
     * @return float
     */
    public function getSubtotal() {
        return array_sum(array_column($this->items, 'subtotal'));
    }
    
    /**
     * 获取折扣
     * @return float
     */
    public function getDiscount() {
        return $this->discount;
    }
    
    /**
     * 获取总价
     * @return float
     */
    public function getTotal() {
        return max(0, $this->getSubtotal() - $this->getDiscount());
    }
    
    /**
     * 保存到会话
     * @return void
     */
    public function saveToSession() {
        $_SESSION['cart'] = [
            'items' => $this->items,
            'discount' => $this->discount
        ];
    }
    
    /**
     * 从会话加载
     * @return void
     */
    public function loadFromSession() {
        if (isset($_SESSION['cart'])) {
            $this->items = $_SESSION['cart']['items'] ?? [];
            $this->discount = $_SESSION['cart']['discount'] ?? 0;
        }
    }
    
    /**
     * 导出为订单数据
     * @return array
     */
    public function toOrderData() {
        return [
            'items' => $this->items,
            'subtotal' => $this->getSubtotal(),
            'discount' => $this->getDiscount(),
            'total' => $this->getTotal(),
            'product_count' => $this->getProductCount(),
            'item_count' => $this->getCount(),
            'created_at' => date('Y-m-d H:i:s')
        ];
    }
    
    /**
     * 更新商品小计
     * @param array &$item 商品项
     * @return void
     */
    private function updateSubtotal(&$item) {
        $item['subtotal'] = $item['price'] * $item['quantity'];
    }
}

// 使用示例
try {
    $cart = new ShoppingCart();
    
    // 添加商品
    $cart->addProduct([
        'id' => 1,
        'name' => 'PHP编程书籍',
        'price' => 99.99,
        'quantity' => 1,
        'sku' => 'PHP-BOOK-001',
        'image' => 'php-book.jpg'
    ]);
    
    $cart->addProduct([
        'id' => 2,
        'name' => '编程鼠标',
        'price' => 199.99,
        'quantity' => 2,
        'sku' => 'MOUSE-001',
        'image' => 'mouse.jpg'
    ]);
    
    // 更新数量
    $cart->updateQuantity(1, 3);
    
    // 设置折扣
    $cart->setDiscount(10, true); // 10%折扣
    
    // 导出订单数据
    $orderData = $cart->toOrderData();
    print_r($orderData);
    
    // 保存到会话
    session_start();
    $cart->saveToSession();
    
} catch (Exception $e) {
    echo '错误: ' . $e->getMessage();
}
?>

用户数据管理系统

<?php
/**
 * 用户数据管理系统
 * 功能:用户分组、排序、筛选、分页、统计分析
 */

class UserManager {
    private $users = [];
    
    /**
     * 构造函数
     * @param array $users 用户数据
     */
    public function __construct(array $users) {
        $this->users = $users;
    }
    
    /**
     * 获取所有用户
     * @return array
     */
    public function getAllUsers() {
        return $this->users;
    }
    
    /**
     * 按字段排序
     * @param string $field 排序字段
     * @param bool $desc 是否降序
     * @return array
     */
    public function sortBy($field, $desc = false) {
        $sorted = $this->users;
        usort($sorted, function($a, $b) use ($field, $desc) {
            if (!isset($a[$field]) || !isset($b[$field])) {
                return 0;
            }
            
            $result = 0;
            if (is_numeric($a[$field]) && is_numeric($b[$field])) {
                $result = $a[$field] <=> $b[$field];
            } else {
                $result = strcmp($a[$field], $b[$field]);
            }
            
            return $desc ? -$result : $result;
        });
        
        return $sorted;
    }
    
    /**
     * 筛选用户
     * @param callable $callback 筛选回调
     * @return array
     */
    public function filter(callable $callback) {
        return array_filter($this->users, $callback);
    }
    
    /**
     * 按年龄分组
     * @return array
     */
    public function groupByAge() {
        $groups = [];
        foreach ($this->users as $user) {
            $ageGroup = floor($user['age'] / 10) * 10;
            $groupName = "{$ageGroup}-" . ($ageGroup + 9) . "岁";
            
            if (!isset($groups[$groupName])) {
                $groups[$groupName] = [];
            }
            
            $groups[$groupName][] = $user;
        }
        
        return $groups;
    }
    
    /**
     * 按分数分级
     * @return array
     */
    public function gradeByScore() {
        $grades = [];
        foreach ($this->users as $user) {
            $score = $user['score'];
            
            if ($score >= 90) {
                $grade = '优秀';
            } elseif ($score >= 80) {
                $grade = '良好';
            } elseif ($score >= 60) {
                $grade = '及格';
            } else {
                $grade = '不及格';
            }
            
            if (!isset($grades[$grade])) {
                $grades[$grade] = [];
            }
            
            $grades[$grade][] = $user;
        }
        
        return $grades;
    }
    
    /**
     * 分页获取用户
     * @param int $page 页码
     * @param int $pageSize 每页数量
     * @return array
     */
    public function paginate($page = 1, $pageSize = 10) {
        $page = max(1, (int)$page);
        $pageSize = max(1, (int)$pageSize);
        
        $offset = ($page - 1) * $pageSize;
        $total = count($this->users);
        $totalPages = ceil($total / $pageSize);
        
        $paginated = array_slice($this->users, $offset, $pageSize);
        
        return [
            'data' => $paginated,
            'pagination' => [
                'current_page' => $page,
                'page_size' => $pageSize,
                'total' => $total,
                'total_pages' => $totalPages,
                'has_prev' => $page > 1,
                'has_next' => $page < $totalPages
            ]
        ];
    }
    
    /**
     * 计算统计数据
     * @return array
     */
    public function getStatistics() {
        $scores = array_column($this->users, 'score');
        $ages = array_column($this->users, 'age');
        
        return [
            'total_users' => count($this->users),
            'average_score' => $scores ? array_sum($scores) / count($scores) : 0,
            'average_age' => $ages ? array_sum($ages) / count($ages) : 0,
            'max_score' => $scores ? max($scores) : 0,
            'min_score' => $scores ? min($scores) : 0,
            'age_distribution' => $this->getAgeDistribution()
        ];
    }
    
    /**
     * 获取年龄分布
     * @return array
     */
    private function getAgeDistribution() {
        $distribution = [];
        foreach ($this->users as $user) {
            $age = $user['age'];
            $distribution[$age] = ($distribution[$age] ?? 0) + 1;
        }
        
        return $distribution;
    }
    
    /**
     * 搜索用户
     * @param string $keyword 关键词
     * @return array
     */
    public function search($keyword) {
        $keyword = trim($keyword);
        if (empty($keyword)) {
            return [];
        }
        
        return array_filter($this->users, function($user) use ($keyword) {
            return strpos($user['name'], $keyword) !== false;
        });
    }
    
    /**
     * 导出为CSV格式
     * @param string $filename 文件名
     * @return bool
     */
    public function exportToCSV($filename) {
        $handle = fopen($filename, 'w');
        if (!$handle) {
            return false;
        }
        
        // 写入表头
        if (!empty($this->users)) {
            fputcsv($handle, array_keys($this->users[0]));
            
            // 写入数据
            foreach ($this->users as $user) {
                fputcsv($handle, $user);
            }
        }
        
        fclose($handle);
        return true;
    }
}

// 使用示例
$users = [
    ["id" => 1, "name" => "张三", "age" => 25, "score" => 85, "email" => "zhangsan@example.com"],
    ["id" => 2, "name" => "李四", "age" => 30, "score" => 92, "email" => "lisi@example.com"],
    ["id" => 3, "name" => "王五", "age" => 20, "score" => 78, "email" => "wangwu@example.com"],
    ["id" => 4, "name" => "赵六", "age" => 28, "score" => 95, "email" => "zhaoliu@example.com"],
    ["id" => 5, "name" => "钱七", "age" => 35, "score" => 88, "email" => "qianqi@example.com"],
    ["id" => 6, "name" => "孙八", "age" => 18, "score" => 65, "email" => "sunba@example.com"]
];

$manager = new UserManager($users);

// 按分数排序
echo "=== 按分数降序排序 ===\n";
$sortedByScore = $manager->sortBy('score', true);
print_r($sortedByScore);

// 筛选成年人
echo "=== 筛选成年人 ===\n";
$adults = $manager->filter(function($user) {
    return $user['age'] >= 18;
});
print_r($adults);

// 按年龄分组
echo "=== 按年龄分组 ===\n";
$ageGroups = $manager->groupByAge();
print_r($ageGroups);

// 按分数分级
echo "=== 按分数分级 ===\n";
$grades = $manager->gradeByScore();
print_r($grades);

// 分页
echo "=== 分页查询 ===\n";
$pagination = $manager->paginate(1, 3);
print_r($pagination);

// 统计数据
echo "=== 统计数据 ===\n";
$stats = $manager->getStatistics();
print_r($stats);

// 搜索用户
echo "=== 搜索用户 ===\n";
$searchResults = $manager->search('张');
print_r($searchResults);

// 导出为CSV
echo "=== 导出CSV ===\n";
if ($manager->exportToCSV('users.csv')) {
    echo "导出成功!";
} else {
    echo "导出失败!";
}
?>

数据统计与分析

<?php
// 销售数据
$sales = [
    ["product" => "A", "category" => "电子产品", "amount" => 100, "price" => 5000],
    ["product" => "B", "category" => "电子产品", "amount" => 150, "price" => 3000],
    ["product" => "C", "category" => "服装", "amount" => 200, "price" => 500],
    ["product" => "D", "category" => "服装", "amount" => 300, "price" => 300],
    ["product" => "E", "category" => "食品", "amount" => 500, "price" => 50]
];

// 计算每个产品的销售额
$salesData = array_map(function($item) {
    $item["total"] = $item["amount"] * $item["price"];
    return $item;
}, $sales);

// 按类别分组统计
$categoryStats = [];
foreach ($salesData as $item) {
    if (!isset($categoryStats[$item["category"]])) {
        $categoryStats[$item["category"]] = [
            "totalAmount" => 0,
            "totalSales" => 0,
            "products" => []
        ];
    }
    $categoryStats[$item["category"]]["totalAmount"] += $item["amount"];
    $categoryStats[$item["category"]]["totalSales"] += $item["total"];
    $categoryStats[$item["category"]]["products"][] = $item["product"];
}

// 找出销售额最高的产品
$topProduct = array_reduce($salesData, function($max, $item) {
    return ($max === null || $item["total"] > $max["total"]) ? $item : $max;
});

print_r($categoryStats);
echo "销售额最高的产品: " . $topProduct["product"] . " (" . $topProduct["total"] . "元)";
?>

数组高级技巧

数组去重

<?php
$numbers = [1, 2, 2, 3, 3, 3, 4, 5, 5];
$unique = array_unique($numbers);  // [1, 2, 3, 4, 5]

// 关联数组去重(根据值)
$users = [
    ["id" => 1, "name" => "张三"],
    ["id" => 2, "name" => "李四"],
    ["id" => 3, "name" => "张三"]
];

$uniqueUsers = array_values(array_unique(array_column($users, null, "name")));
?>

数组翻转

<?php
$arr = ["a", "b", "c"];
$reversed = array_reverse($arr);  // ["c", "b", "a"]

// 键值互换
$map = ["a" => 1, "b" => 2, "c" => 3];
$flipped = array_flip($map);  // [1 => "a", 2 => "b", 3 => "c"]
?>

数组统计

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

count($numbers);      // 5 - 元素个数
array_sum($numbers);  // 15 - 求和
array_product($numbers); // 120 - 求积

// 计数值出现次数
$votes = ["A", "B", "A", "C", "A", "B"];
$counts = array_count_values($votes);
// ["A" => 3, "B" => 2, "C" => 1]

// 计算最大值、最小值
$max = max($numbers);
$min = min($numbers);

// 计算中位数
function calculateMedian($arr) {
    sort($arr);
    $count = count($arr);
    $mid = floor($count / 2);
    return $count % 2 ? $arr[$mid] : ($arr[$mid - 1] + $arr[$mid]) / 2;
}
?>

数组性能优化

大数组处理技巧:
<?php
// 使用生成器处理大文件
function readLargeFile($filename) {
    $handle = fopen($filename, 'r');
    while (($line = fgets($handle)) !== false) {
        yield trim($line);
    }
    fclose($handle);
}

// 分批处理数组
function processBatch($items, $batchSize, $processor) {
    $batches = array_chunk($items, $batchSize);
    foreach ($batches as $batch) {
        $processor($batch);
    }
}

// 使用SplFixedArray
$fixedArray = new SplFixedArray(100000);
for ($i = 0; $i < 100000; $i++) {
    $fixedArray[$i] = $i;
}
?>
最佳实践:

实践练习

  1. 数组创建:创建学生信息数组,包含姓名、年龄、成绩
  2. 数组操作:实现购物车功能(添加、删除、修改商品)
  3. 数组排序:按成绩对学生数组进行排序
  4. 数组过滤:从数组中筛选出及格的成绩
  5. 数组映射:将价格数组中的每个价格打9折
  6. 数组统计:计算数组中的最大值、最小值、平均值
  7. 多维数组:创建并遍历班级学生成绩表
  8. 数组去重:从用户输入中去除重复的标签