索引数组
索引数组是PHP中最基础的数组类型,使用数字作为键(索引)来访问数组元素。索引从0开始自动递增,是处理有序数据集合的理想选择。
什么是索引数组?
索引数组(Indexed Array)是使用整数作为键的数组。在PHP中,如果没有指定键,数组会自动从0开始分配连续的整数索引。
// 基本的索引数组
$fruits = ["苹果", "香蕉", "橙子", "葡萄"];
// 索引: 0 1 2 3
创建索引数组
1. 使用数组字面量(推荐)
// 空数组
$emptyArray = [];
// 包含元素的数组
$numbers = [1, 2, 3, 4, 5];
// 混合类型的数组
$mixed = [42, "Hello", 3.14, true];
2. 使用array()函数
// 等同于上面的数组字面量写法
$numbers = array(1, 2, 3, 4, 5);
$mixed = array(42, "Hello", 3.14, true);
3. 动态添加元素
// 逐步创建数组
$students = [];
$students[] = "张三"; // 自动分配索引0
$students[] = "李四"; // 自动分配索引1
$students[] = "王五"; // 自动分配索引2
// 显式指定索引
$scores = [];
$scores[0] = 85;
$scores[1] = 92;
$scores[2] = 78;
4. 使用range()函数创建序列
// 创建数字序列
$numbers1 = range(1, 10); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
$numbers2 = range(0, 100, 10); // [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
// 创建字母序列
$letters = range('a', 'z'); // ['a', 'b', 'c', ..., 'z']
$uppercase = range('A', 'Z'); // ['A', 'B', 'C', ..., 'Z']
访问数组元素
1. 通过索引访问
$colors = ["红色", "绿色", "蓝色", "黄色"];
// 访问单个元素
echo $colors[0]; // 输出:红色
echo $colors[2]; // 输出:蓝色
// 修改元素
$colors[1] = "浅绿色";
echo $colors[1]; // 输出:浅绿色
2. 负索引访问(PHP 8.0+)
$fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"];
// 从数组末尾开始计数
echo $fruits[-1]; // 输出:西瓜(最后一个元素)
echo $fruits[-2]; // 输出:葡萄(倒数第二个元素)
// 修改负索引对应的元素
$fruits[-1] = "哈密瓜";
遍历索引数组
1. for循环
$grades = [85, 92, 78, 96, 88];
$total = 0;
$count = count($grades);
for ($i = 0; $i < $count; $i++) {
echo "成绩 {$i}: {$grades[$i]}\n";
$total += $grades[$i];
}
$average = $total / $count;
echo "平均分:{$average}";
2. foreach循环(推荐)
$products = ["iPhone", "MacBook", "iPad", "AirPods"];
// 只获取值
foreach ($products as $product) {
echo "商品:{$product}\n";
}
// 获取键和值
foreach ($products as $index => $product) {
echo "编号 {$index}: {$product}\n";
}
3. while循环配合list()
$students = ["张三", "李四", "王五", "赵六"];
// 传统方式
$i = 0;
while ($i < count($students)) {
echo "学生 {$i}: {$students[$i]}\n";
$i++;
}
// 使用each()函数(PHP 7.2后已废弃,了解即可)
// reset($students);
// while (list($key, $value) = each($students)) {
// echo "学生 {$key}: {$value}\n";
// }
常用操作
1. 添加元素
$cities = ["北京", "上海", "广州"];
// 在末尾添加元素
array_push($cities, "深圳");
array_push($cities, "杭州", "南京"); // 可同时添加多个
// 等效的简写方式
$cities[] = "成都";
// 在开头插入元素
array_unshift($cities, "重庆");
2. 删除元素
$numbers = [10, 20, 30, 40, 50];
// 删除末尾元素
$last = array_pop($numbers); // 返回50,数组变为[10, 20, 30, 40]
// 删除开头元素
$first = array_shift($numbers); // 返回10,数组变为[20, 30, 40]
// 删除指定索引的元素
unset($numbers[1]); // 删除索引1的元素,数组变为[20, 40]
// 注意:unset()不会重新索引,索引可能不连续
// 如果需要重新索引,可以使用array_values()
$numbers = array_values($numbers);
3. 查找元素
$fruits = ["苹果", "香蕉", "橙子", "葡萄", "苹果"];
// 检查元素是否存在(值)
if (in_array("苹果", $fruits)) {
echo "找到了苹果!";
}
// 获取元素的键(索引)
$index = array_search("橙子", $fruits); // 返回2
$notFound = array_search("西瓜", $fruits); // 返回false
// 注意:如果元素值是0或空字符串,需要严格比较
$index = array_search("苹果", $fruits, true); // 严格比较
4. 数组合并与拆分
$array1 = ["a", "b", "c"];
$array2 = ["d", "e", "f"];
$array3 = ["g", "h"];
// 合并数组
$merged = array_merge($array1, $array2, $array3);
// 结果:["a", "b", "c", "d", "e", "f", "g", "h"]
// 使用+运算符合并(保留原始键)
$merged2 = $array1 + $array2;
// 结果:["a", "b", "c", "d", "e", "f"]
// 取数组的一部分
$slice = array_slice($merged, 2, 4); // 从索引2开始取4个元素
// 结果:["c", "d", "e", "f"]
// 移除数组的一部分并替换
$replaced = array_splice($merged, 1, 3, ["x", "y", "z"]);
// merged变为:["a", "x", "y", "z", "f", "g", "h"]
// replaced返回:["b", "c", "d"]
实际应用示例
1. 学生成绩管理系统
<?php
class StudentGradeManager {
private $students = []; // 学生姓名数组
private $grades = []; // 成绩数组
private $subjects = []; // 科目数组
public function __construct() {
// 初始化科目
$this->subjects = ["语文", "数学", "英语", "物理", "化学"];
}
// 添加学生
public function addStudent($name) {
if (!in_array($name, $this->students)) {
$this->students[] = $name;
// 为新学生初始化成绩数组
$studentIndex = array_search($name, $this->students);
$this->grades[$studentIndex] = array_fill(0, count($this->subjects), 0);
return true;
}
return false;
}
// 设置学生成绩
public function setGrade($studentName, $subjectIndex, $grade) {
$studentIndex = array_search($studentName, $this->students);
if ($studentIndex !== false && isset($this->grades[$studentIndex][$subjectIndex])) {
$this->grades[$studentIndex][$subjectIndex] = $grade;
return true;
}
return false;
}
// 计算学生总分
public function getTotalScore($studentName) {
$studentIndex = array_search($studentName, $this->students);
if ($studentIndex !== false) {
return array_sum($this->grades[$studentIndex]);
}
return 0;
}
// 计算学生平均分
public function getAverageScore($studentName) {
$total = $this->getTotalScore($studentName);
$studentIndex = array_search($studentName, $this->students);
if ($studentIndex !== false && count($this->grades[$studentIndex]) > 0) {
return $total / count($this->grades[$studentIndex]);
}
return 0;
}
// 获取班级排名
public function getClassRanking() {
$rankings = [];
foreach ($this->students as $index => $student) {
$totalScore = $this->getTotalScore($student);
$rankings[] = [
'name' => $student,
'total' => $totalScore,
'average' => $this->getAverageScore($student)
];
}
// 按总分降序排序
usort($rankings, function($a, $b) {
return $b['total'] - $a['total'];
});
return $rankings;
}
// 获取科目平均分
public function getSubjectAverages() {
$subjectAverages = [];
$studentCount = count($this->students);
if ($studentCount === 0) {
return $subjectAverages;
}
foreach ($this->subjects as $subjectIndex => $subject) {
$subjectTotal = 0;
foreach ($this->grades as $studentGrades) {
$subjectTotal += $studentGrades[$subjectIndex];
}
$subjectAverages[$subject] = $subjectTotal / $studentCount;
}
return $subjectAverages;
}
// 显示成绩单
public function displayReportCard() {
echo "=== 成绩单 ===\n\n";
// 表头
printf("%-10s", "姓名");
foreach ($this->subjects as $subject) {
printf("%-8s", $subject);
}
printf("%-8s %-8s\n", "总分", "平均分");
echo str_repeat("-", 60) . "\n";
// 学生成绩
$rankings = $this->getClassRanking();
foreach ($rankings as $rank => $student) {
$studentIndex = array_search($student['name'], $this->students);
printf("%-10s", $student['name']);
foreach ($this->grades[$studentIndex] as $grade) {
printf("%-8d", $grade);
}
printf("%-8.1f %-8.1f\n", $student['total'], $student['average']);
}
// 科目平均分
echo "\n科目平均分:\n";
$subjectAverages = $this->getSubjectAverages();
foreach ($subjectAverages as $subject => $average) {
echo "{$subject}: {$average:.1f}\n";
}
}
}
// 使用示例
$manager = new StudentGradeManager();
// 添加学生
$manager->addStudent("张三");
$manager->addStudent("李四");
$manager->addStudent("王五");
$manager->addStudent("赵六");
// 设置成绩
$manager->setGrade("张三", 0, 85); // 语文
$manager->setGrade("张三", 1, 92); // 数学
$manager->setGrade("张三", 2, 88); // 英语
$manager->setGrade("张三", 3, 90); // 物理
$manager->setGrade("张三", 4, 87); // 化学
$manager->setGrade("李四", 0, 78);
$manager->setGrade("李四", 1, 95);
$manager->setGrade("李四", 2, 82);
$manager->setGrade("李四", 3, 88);
$manager->setGrade("李四", 4, 91);
$manager->setGrade("王五", 0, 92);
$manager->setGrade("王五", 1, 88);
$manager->setGrade("王五", 2, 90);
$manager->setGrade("王五", 3, 85);
$manager->setGrade("王五", 4, 89);
$manager->setGrade("赵六", 0, 80);
$manager->setGrade("赵六", 1, 85);
$manager->setGrade("赵六", 2, 78);
$manager->setGrade("赵六", 3, 82);
$manager->setGrade("赵六", 4, 80);
// 显示成绩单
$manager->displayReportCard();
?>
2. 简单的待办事项管理
<?php
class TodoList {
private $tasks = [];
private $completed = [];
// 添加任务
public function addTask($task) {
$this->tasks[] = $task;
$this->completed[] = false;
return count($this->tasks) - 1;
}
// 完成任务
public function completeTask($index) {
if (isset($this->tasks[$index])) {
$this->completed[$index] = true;
return true;
}
return false;
}
// 删除任务
public function removeTask($index) {
if (isset($this->tasks[$index])) {
unset($this->tasks[$index]);
unset($this->completed[$index]);
// 重新索引
$this->tasks = array_values($this->tasks);
$this->completed = array_values($this->completed);
return true;
}
return false;
}
// 显示所有任务
public function displayTasks() {
if (empty($this->tasks)) {
echo "没有待办事项。\n";
return;
}
echo "=== 待办事项 ===\n";
foreach ($this->tasks as $index => $task) {
$status = $this->completed[$index] ? "✓" : "○";
echo "{$index}. [{$status}] {$task}\n";
}
echo "\n";
}
// 显示统计
public function displayStats() {
$total = count($this->tasks);
$done = count(array_filter($this->completed));
$pending = $total - $done;
echo "=== 统计信息 ===\n";
echo "总任务数:{$total}\n";
echo "已完成:{$done}\n";
echo "待完成:{$pending}\n";
if ($total > 0) {
echo "完成率:" . round(($done / $total) * 100, 1) . "%\n";
}
}
}
// 使用示例
$todo = new TodoList();
// 添加任务
$todo->addTask("学习PHP数组");
$todo->addTask("完成作业");
$todo->addTask("锻炼身体");
$todo->addTask("阅读技术书籍");
// 显示任务
$todo->displayTasks();
// 完成一些任务
$todo->completeTask(0);
$todo->completeTask(2);
// 再次显示
$todo->displayTasks();
$todo->displayStats();
// 删除一个任务
$todo->removeTask(1);
echo "\n删除任务后:\n";
$todo->displayTasks();
?>
常见错误和解决方案
1. 索引越界错误
// 错误示例
$colors = ["红色", "绿色", "蓝色"];
echo $colors[3]; // Notice: Undefined offset
// 正确做法:检查索引是否存在
if (isset($colors[2])) {
echo $colors[2];
}
// 或者使用null合并运算符(PHP 7.0+)
echo $colors[3] ?? "默认颜色";
2. 混淆键和值
// 错误:把值当作索引使用
$names = ["张三", "李四", "王五"];
echo $names["张三"]; // 错误,"张三"是值,不是键
// 正确:查找值的索引
$index = array_search("张三", $names);
if ($index !== false) {
echo $names[$index];
}
3. 删除元素后的索引问题
$array = [10, 20, 30, 40, 50];
unset($array[2]); // 删除30
print_r($array);
// 输出:Array([0] => 10 [1] => 20 [3] => 40 [4] => 50)
// 注意索引2被跳过了
// 如果需要连续索引,重新索引数组
$array = array_values($array);
print_r($array);
// 输出:Array([0] => 10 [1] => 20 [2] => 40 [3] => 50)
4. 数组拷贝问题
$array1 = [1, 2, 3];
$array2 = $array1; // 值拷贝
$array2[] = 4; // 只影响$array2
// $array1 仍然是 [1, 2, 3]
// $array2 变为 [1, 2, 3, 4]
// 如果需要引用拷贝
$array3 = &$array1;
$array3[] = 5; // 两个数组都会被修改
性能优化建议
1. 选择合适的遍历方式
$largeArray = range(1, 100000);
// foreach通常比for循环更快,且更简洁
foreach ($largeArray as $value) {
// 处理元素
}
// for循环需要额外调用count()
// for ($i = 0; $i < count($largeArray); $i++) {
// // 每次循环都调用count(),效率较低
// }
// 优化:提前计算长度
$length = count($largeArray);
for ($i = 0; $i < $length; $i++) {
// 处理元素
}
2. 避免不必要的数组操作
// 不好的做法:频繁添加元素
$array = [];
for ($i = 0; $i < 10000; $i++) {
$array[] = $i;
}
// 好的做法:如果知道大小,预分配
// PHP数组会自动扩展,但理解这个概念有助于性能优化
练习题
基础练习
-
创建和访问数组
// 创建一个包含5个水果名称的数组 // 访问第3个水果并打印 // 修改第2个水果的值 // 在数组末尾添加一个新水果 -
数组遍历
// 创建一个数字数组1-10 // 使用for循环计算所有偶数的和 // 使用foreach循环打印所有奇数
进阶练习
-
数组操作
// 实现一个函数,接收一个数组,返回最大值和最小值 // 实现一个函数,判断数组是否是递增的 // 实现一个函数,移除数组中的重复元素 -
数组统计
// 给定成绩数组,计算平均分、最高分、最低分 // 统计每个分数段的人数(90-100, 80-89, 70-79, 60-69, <60)
实战练习
-
简单的库存管理
// 创建一个Product类,使用索引数组管理商品 // 实现添加、删除、查找商品功能 // 实现库存盘点功能 -
数据分析工具
// 读取一组销售数据(日期、销售额) // 计算总销售额、平均销售额 // 找出销售额最高和最低的日期 // 统计月度销售趋势
总结
索引数组是PHP编程的基础,掌握好索引数组的使用对于编写高效的PHP程序至关重要。通过本节的学习,你应该:
- 理解索引数组的概念和特点
- 掌握创建、访问、修改索引数组的方法
- 熟练使用各种数组遍历方式
- 了解常用的数组操作函数
- 能够在实际项目中应用索引数组
接下来,我们将学习关联数组,它将为我们提供更灵活的数据组织方式。