PHP: 实战:数组与函数综合
学了 14 课的语法和函数,是时候把它们串起来了。这三个项目从简单到复杂,让你真正用 PHP 做出可运行的应用。
1. 准备工作
在你之前创建的 htdocs/myphp/ 目录下新建 practice/ 文件夹,所有练习放这里。通过 http://localhost/myphp/practice/ 访问。
2. 项目一:购物车
用数组模拟一个购物车,支持添加商品、修改数量、删除商品、计算总价。
PHP
<?php
// cart.php - 购物车系统
/**
* 添加商品到购物车
* @param array $cart 购物车引用
* @param string $name 商品名
* @param float $price 单价
* @param int $qty 数量(默认1)
* @return void
*/
function addItem(array &$cart, string $name, float $price, int $qty = 1): void {
if (isset($cart[$name])) {
$cart[$name]['qty'] += $qty;
} else {
$cart[$name] = ['price' => $price, 'qty' => $qty];
}
}
/**
* 修改商品数量
*/
function updateQty(array &$cart, string $name, int $qty): void {
if ($qty <= 0) {
unset($cart[$name]);
} elseif (isset($cart[$name])) {
$cart[$name]['qty'] = $qty;
}
}
/**
* 删除商品
*/
function removeItem(array &$cart, string $name): void {
unset($cart[$name]);
}
/**
* 计算总价
*/
function getTotal(array $cart): float {
return array_sum(array_map(
fn($item) => $item['price'] * $item['qty'],
$cart
));
}
// === 测试购物车 ===
$cart = [];
addItem($cart, "PHP教程", 39.90, 2);
addItem($cart, "MySQL入门", 29.90, 1);
addItem($cart, "PHP教程", 39.90, 1); // 追加1本
echo "<pre>";
echo "购物车内容:\n";
print_r($cart);
echo "\n总价:¥" . getTotal($cart) . "\n";
// 修改数量
updateQty($cart, "MySQL入门", 3);
echo "\n修改后总价:¥" . getTotal($cart) . "\n";
// 删除
removeItem($cart, "PHP教程");
echo "\n删除后:\n";
print_r($cart);
echo "\n最终总价:¥" . getTotal($cart) . "\n";
echo "</pre>";
?>
💡 提示: 这个购物车所有数据存在内存中,刷新页面就会清空。第 21 课学了 Session 之后,购物车就能"记住"你的商品了。
3. 项目二:待办事项列表
用数组管理待办事项:添加、完成、删除、按状态过滤、排序。
▶ 示例:Todo 应用
PHP
📖 仅展示
<?php
// todo.php - 待办事项
/**
* 添加任务
*/
function addTodo(array &$todos, string $title, string $priority = "medium"): void {
$todos[] = [
'id' => count($todos) + 1,
'title' => $title,
'done' => false,
'priority' => $priority,
'created' => date("Y-m-d H:i:s"),
];
}
/**
* 标记完成
*/
function markDone(array &$todos, int $id): void {
foreach ($todos as &$todo) {
if ($todo['id'] === $id) {
$todo['done'] = true;
break;
}
}
}
/**
* 删除任务
*/
function deleteTodo(array &$todos, int $id): void {
$todos = array_filter($todos, fn($t) => $t['id'] !== $id);
}
/**
* 获取未完成的任务
*/
function getPending(array $todos): array {
return array_filter($todos, fn($t) => !$t['done']);
}
/**
* 统计完成情况
*/
function getStats(array $todos): array {
$total = count($todos);
$done = count(array_filter($todos, fn($t) => $t['done']));
return ['total' => $total, 'done' => $done, 'pending' => $total - $done];
}
// === 测试 Todo ===
$todos = [];
addTodo($todos, "学习 PHP 数组", "high");
addTodo($todos, "练习 foreach 循环", "medium");
addTodo($todos, "写购物车函数", "high");
addTodo($todos, "复习日期函数", "low");
markDone($todos, 1);
markDone($todos, 3);
$stats = getStats($todos);
echo "总计:{$stats['total']},已完成:{$stats['done']},待办:{$stats['pending']}<br>";
echo "<h3>待办事项</h3>";
foreach (getPending($todos) as $todo) {
$priorityEmoji = [
'high' => '🔴',
'medium' => '🟡',
'low' => '🟢',
];
echo $priorityEmoji[$todo['priority']] . " {$todo['title']}<br>";
}
?>
4. 项目三:简易投票系统
用关联数组存储选项和票数,支持投票、查看结果、按票数排序。
▶ 示例:投票系统
PHP
📖 仅展示
<?php
// vote.php - 简易投票
function createPoll(array $options): array {
return array_fill_keys($options, 0);
}
function vote(array &$poll, string $option): bool {
if (!array_key_exists($option, $poll)) {
return false;
}
$poll[$option]++;
return true;
}
function getResults(array $poll): array {
arsort($poll); // 按票数降序
return $poll;
}
function getTotalVotes(array $poll): int {
return array_sum($poll);
}
function getWinner(array $poll): ?string {
$results = getResults($poll);
$maxVotes = max($results);
if ($maxVotes === 0) return null;
return array_key_first($results);
}
// === 测试投票 ===
$poll = createPoll(["PHP", "Python", "JavaScript", "Go", "Rust"]);
vote($poll, "PHP");
vote($poll, "PHP");
vote($poll, "JavaScript");
vote($poll, "Python");
vote($poll, "PHP");
vote($poll, "Rust");
vote($poll, "Python");
echo "<h3>投票结果</h3>";
echo "总票数:" . getTotalVotes($poll) . "<br>";
$results = getResults($poll);
foreach ($results as $lang => $votes) {
$percent = round($votes / getTotalVotes($poll) * 100, 1);
$bar = str_repeat("█", $votes);
echo "{$lang}:{$bar} {$votes}票 ({$percent}%)<br>";
}
echo "<br>🏆 领先者:" . getWinner($poll) . "<br>";
?>
5. 反思:从脚本到应用
这三个项目让你看到:
- 数组不只能存数据,还能表达复杂业务逻辑
- 函数把操作封装起来,代码更干净
- 引用传递(&$arr) 让函数能直接修改外部数据结构
- array_map + 箭头函数 让数据处理简洁高效
但你也该注意到了这些限制:
- 数据都在内存里,刷新就没了(后面用 Session / 数据库解决)
- 代码和界面混在一起(后面用 MVC 架构解决)
- 没有表单交互(下一课就开始学)
❓ 常见问题
Q 为什么购物车用关联数组而不是索引数组?
A 关联数组用商品名做键,查找和修改 O(1)。索引数组需要遍历查找,商品多了会很慢。
Q
array_fill_keys 是什么?A
array_fill_keys(['a','b'], 0) 返回 ['a'=>0, 'b'=>0],一次把多个键设为相同值。投票系统里用它初始化所有选项为 0 票。Q 这些项目的数据会保存吗?
A 不会,刷新页面全部清空。这是 PHP 的"无状态"特性。第 21 课学习 Session 后,购物车的数据就能在用户会话期间保持。
📖 小节
- 购物车系统:关联数组 + 引用传递 + 引用计数更新
- 待办事项:多维数组 + array_filter 过滤 + 统计
- 投票系统:array_fill_keys 初始化 + arsort 排序 + array_key_first
- 从练习中理解"无状态"限制 → 驱动后续学习 Session/数据库
📝 作业
- 为购物车系统添加更多商品(至少 5 种),实现"清空购物车"函数。
- 为待办事项系统添加"按优先级排序"功能(high > medium > low)。
- 为投票系统添加"防刷票"逻辑:用函数判断该选项是否在投票范围内,无效选项拒绝投票。