单元1 · PHP 环境与基础语法
安装与运行、echo、变量、常量、注释、字符串
- 标签:PHP 代码在 中,CLI 或 Web 均可运行。
- 变量:以 $ 开头、动态类型;var_dump 查看类型。
- 常量:define() 或 const 定义,全大写命名惯例。
实训1.1 Hello World 与输出
编写第一个 PHP 脚本,用 echo 输出问候语,并说明 PHP 的标签写法。
PHP 代码写在 中;echo 输出内容;在浏览器或 CLI 运行。
<?php
// 这是单行注释
echo "Hello, PHP!\n";
/* 这是多行注释 */
$name = "World";
echo "Hello, $name!\n";
?>
实训1.2 变量与数据类型
声明字符串、整数、浮点、布尔变量并输出,用 var_dump 查看类型。
PHP 变量以 $ 开头、无需声明类型;var_dump 输出类型与值。
<?php
$name = "PHP";
$version = 8.3;
$isPopular = true;
$year = 2026;
echo "语言:$name\n";
echo "版本:$version\n";
var_dump($name);
var_dump($version);
var_dump($isPopular);
var_dump($year);
?>
实训1.3 常量与字符串拼接
用 define 和 const 定义常量,输出常量值并用 . 拼接字符串。
define('名字', 值) 或 const 定义常量;字符串拼接用 . 运算符。
<?php
define("SITE_NAME", "Helpme");
const MAX_USERS = 100;
echo "站点:" . SITE_NAME . "\n";
echo "最大用户数:" . MAX_USERS . "\n";
$lang = "PHP";
$msg = "正在学习" . $lang;
echo $msg . "\n";
?>
实训1.4 heredoc 与变量插值
用 heredoc 语法输出多行文本并插入变量值。
heredoc 用 <<
<?php
$name = "Marvis";
$text = <<<EOT
你好,$name!
这是 heredoc 多行文本。
支持变量插值与"引号"。
EOT;
echo $text;
?>
单元2 · 数据类型与运算符
类型、算术/比较/逻辑运算符、类型转换
- 运算:/ 浮点除法、intdiv 整除、% 取余、** 幂。
- 比较:=== 严格相等;== 宽松相等有类型转换。
- 合并:?? 空值合并;?: 三元简写。
实训2.1 基础运算
给定整数 17 和 5,输出和、差、积、商(整除)、余数与幂。
PHP 中 / 返回浮点(若可整除则返回整数形式);intdiv 整除;% 取余;** 幂。
<?php
$a = 17;
$b = 5;
echo "和:" . ($a + $b) . "\n";
echo "差:" . ($a - $b) . "\n";
echo "积:" . ($a * $b) . "\n";
echo "商:" . ($a / $b) . "\n";
echo "整除:" . intdiv($a, $b) . "\n";
echo "余数:" . ($a % $b) . "\n";
echo "幂:" . ($a ** $b) . "\n";
?>
实训2.2 比较与逻辑运算
a=8、b=12,输出 a>b、a!==b、a<10 && b>10、!(a===8) 的结果。
=== 严格相等、!== 严格不等;&& 与、|| 或、! 非。
<?php
$a = 8;
$b = 12;
var_dump($a > $b);
var_dump($a !== $b);
var_dump($a < 10 && $b > 10);
var_dump(!($a === 8));
?>
实训2.3 类型转换
把字符串 '42' 转 int 加 8,再转 float 与字符串,输出各自类型。
(int)/(float)/(string) 强制转换;gettype 查看类型。
<?php
$s = "42";
$n = (int)$s + 8;
$f = (float)$n;
$t = (string)$f;
echo "整数:$n,类型:" . gettype($n) . "\n";
echo "浮点:$f,类型:" . gettype($f) . "\n";
echo "字符串:$t,类型:" . gettype($t) . "\n";
?>
实训2.4 合并运算符与空值判断
演示 ?? 空值合并与 ?: 三元简写的区别。
$a ?? $b 在 $a 未设置或为 null 时取 $b;?: 在 $a 为假值时取 $b。
<?php
$config = null;
$port = $config ?? 8080;
echo "端口:" . $port . "\n";
$username = "";
$display = $username ?: "游客";
echo "显示名:" . $display . "\n";
$real = "admin";
echo "真实名:" . ($real ?: "游客") . "\n";
?>
单元3 · 流程控制:分支结构
if/elseif/else、switch、match 表达式
- 分支:if/elseif/else 逐级判断。
- switch:case + break + default 多分支。
- match:表达式有返回值,多值用逗号,无需 break。
实训3.1 if 判断成绩等级
成绩 score=85,输出等级:>=90 优秀、>=80 良好、>=60 及格、否则不及格。
PHP 用 elseif 连接多个分支。
<?php
$score = 85;
if ($score >= 90) {
echo "优秀\n";
} elseif ($score >= 80) {
echo "良好\n";
} elseif ($score >= 60) {
echo "及格\n";
} else {
echo "不及格\n";
}
?>
实训3.2 switch 判断星期
用 switch 把数字 1-7 映射为星期,输入 4 输出对应星期。
switch 匹配 case;每支 break;default 兜底。
<?php
$day = 4;
switch ($day) {
case 1: echo "星期一\n"; break;
case 2: echo "星期二\n"; break;
case 3: echo "星期三\n"; break;
case 4: echo "星期四\n"; break;
case 5: echo "星期五\n"; break;
case 6: echo "星期六\n"; break;
case 7: echo "星期日\n"; break;
default: echo "无效输入\n";
}
?>
实训3.3 match 表达式
用 match 表达式把 HTTP 状态码映射为中文描述。
match 是表达式(有返回值),无需 break;用逗号分隔多值。
<?php
$code = 404;
$desc = match ($code) {
200, 201 => "成功",
301, 302 => "重定向",
400, 403, 404 => "客户端错误",
500, 502, 503 => "服务器错误",
default => "未知状态",
};
echo "状态码 $code:$desc\n";
?>
单元4 · 循环结构
for、while、foreach、break/continue
- for:标准三要素循环。
- foreach:遍历数组的推荐方式,可取键和值。
- 控制:break 终止、continue 跳过。
实训4.1 for 求和 1 到 100
用 for 循环计算 1+2+...+100 的和并输出。
标准 for 三要素;累加器初始 0。
<?php
$sum = 0;
for ($i = 1; $i <= 100; $i++) {
$sum += $i;
}
echo "1 到 100 的和:" . $sum . "\n";
?>
实训4.2 打印乘法表
输出 9x9 乘法表,每行一个乘数。
嵌套两层 for;内层随外层变化;\t 对齐。
<?php
for ($i = 1; $i <= 9; $i++) {
$row = "";
for ($j = 1; $j <= $i; $j++) {
$row .= "{$j}x{$i}=" . ($i * $j) . " ";
}
echo $row . "\n";
}
?>
实训4.3 foreach 遍历数组
遍历成绩数组 [55,90,72,88,45],输出及格者及其索引。
foreach ($arr as $k => $v) 同时取键和值;continue 跳过。
<?php
$scores = [55, 90, 72, 88, 45];
foreach ($scores as $index => $score) {
if ($score < 60) {
continue;
}
echo "索引 $index 成绩 $score 及格\n";
}
?>
实训4.4 while 与 break 综合
用 while 输出 1 到 20 中能被 3 整除的数,遇到 15 用 break 结束。
while 条件驱动;break 提前终止;配合 continue 过滤。
<?php
$i = 1;
while ($i <= 20) {
if ($i === 15) {
break;
}
if ($i % 3 === 0) {
echo $i . "\n";
}
$i++;
}
?>
单元5 · 函数
函数定义、参数默认值、可变参数、返回值、作用域
- 定义:function 关键字;return 返回值。
- 参数:默认参数、可变参数 ...$nums。
- 类型:参数/返回类型声明 + strict_types。
实训5.1 定义求和函数
定义 add($a, $b) 返回两数之和并调用输出。
function 关键字定义;return 返回值;参数可指定类型。
<?php
function add($a, $b) {
return $a + $b;
}
echo "add(10, 20) = " . add(10, 20) . "\n";
echo "add(3.5, 2.5) = " . add(3.5, 2.5) . "\n";
?>
实训5.2 默认参数与可变参数
定义 greet($name, $greeting='你好') 带默认参数;定义 sumAll(...$nums) 求和。
默认参数在未传时生效;...$nums 收集可变参数为数组。
<?php
function greet($name, $greeting = "你好") {
return "$greeting,$name!";
}
echo greet("小明") . "\n";
echo greet("小红", "早上好") . "\n";
function sumAll(...$nums) {
return array_sum($nums);
}
echo "sumAll(1,2,3) = " . sumAll(1, 2, 3) . "\n";
echo "sumAll(1,2,3,4,5) = " . sumAll(1, 2, 3, 4, 5) . "\n";
?>
实训5.3 类型声明与严格模式
定义带 int/float 类型声明的函数,并说明 declare(strict_types=1) 的作用。
参数与返回类型声明提升健壮性;严格模式下不自动转换类型。
<?php
declare(strict_types=1);
function calculate(int $a, int $b): int {
return $a * $b + 10;
}
echo calculate(4, 5) . "\n"; // 30
// echo calculate("4", 5); // 严格模式下会报错
?>
单元6 · 数组
索引数组、关联数组、遍历、常用数组函数
- 索引数组:[] 添加、unset 删除、count 统计。
- 关联数组:'键' => 值;foreach 遍历。
- 函数:array_map/filter/unique/merge/count_values。
实训6.1 索引数组操作
创建水果数组,用 [] 添加、unset 删除、count 统计、in_array 判断。
array_push/$arr[]= 添加;unset 删除键;count 计数;in_array 判断。
<?php
$fruits = ["苹果", "香蕉"];
$fruits[] = "橙子";
array_unshift($fruits, "葡萄");
echo "数量:" . count($fruits) . "\n";
print_r($fruits);
unset($fruits[0]);
echo "是否含香蕉:" . (in_array("香蕉", $fruits) ? "是" : "否") . "\n";
?>
实训6.2 关联数组
创建学生成绩关联数组,输出指定科目成绩,遍历输出全部,新增科目。
关联数组用 '键' => 值 定义;foreach 遍历键值。
<?php
$scores = [
"语文" => 90,
"数学" => 85,
"英语" => 92,
];
echo "数学成绩:" . $scores["数学"] . "\n";
$scores["物理"] = 88;
foreach ($scores as $subject => $score) {
echo "$subject:$score 分\n";
}
?>
实训6.3 排序与查找
对数组 [3,1,4,1,5,9,2,6] 去重、排序、用 array_map 生成描述字符串。
array_unique 去重;sort 升序;array_map 映射回调。
<?php
$nums = [3, 1, 4, 1, 5, 9, 2, 6];
$unique = array_unique($nums);
sort($unique);
print_r($unique);
$descs = array_map(fn($n) => "数字$n", $unique);
echo implode(",", $descs) . "\n";
echo "最大值:" . max($nums) . ",最小值:" . min($nums) . "\n";
?>
实训6.4 数组合并与统计
合并两个数组、统计元素出现次数、array_filter 过滤偶数。
array_merge 合并;array_count_values 统计频次;array_filter 过滤。
<?php
$a = [1, 2, 3];
$b = [3, 4, 5];
$merged = array_merge($a, $b);
echo "合并:" . implode(",", $merged) . "\n";
$words = ["php", "js", "php", "go", "php"];
$freq = array_count_values($words);
print_r($freq);
$even = array_filter($merged, fn($n) => $n % 2 === 0);
echo "偶数:" . implode(",", $even) . "\n";
?>
单元7 · 字符串处理
常用字符串函数、正则、格式化
- 基础:trim/strtoupper/str_replace/explode/implode。
- 查找:strpos/substr_count/substr/str_contains。
- 正则:preg_match/preg_replace/preg_split。
实训7.1 字符串常用函数
对字符串 ' Hello, PHP ' 去空格、转大小写、替换、拆分、拼接。
trim/strtoupper/str_replace/explode/implode 是常用函数。
<?php
$s = " Hello, PHP ";
echo "trim:" . trim($s) . "\n";
echo "大写:" . strtoupper(trim($s)) . "\n";
echo "替换:" . str_replace("PHP", "Hypertext Preprocessor", trim($s)) . "\n";
$parts = explode(",", trim($s));
print_r($parts);
echo "拼接:" . implode(" | ", $parts) . "\n";
?>
实训7.2 字符串查找与截取
查找子串位置、统计出现次数、按位置截取子串。
strpos 查找位置;substr_count 统计次数;substr 截取。
<?php
$text = "PHP 是最好的语言之一,PHP 语法灵活。";
echo "PHP 首次出现位置:" . strpos($text, "PHP") . "\n";
echo "PHP 出现次数:" . substr_count($text, "PHP") . "\n";
echo "截取前 9 个字符:" . substr($text, 0, 9) . "\n";
echo "包含 PHP:" . (str_contains($text, "PHP") ? "是" : "否") . "\n";
?>
实训7.3 正则表达式匹配
用 preg_match 校验邮箱格式、preg_replace 替换数字、preg_split 按多个分隔符拆分。
preg_match 返回是否匹配;preg_replace 替换;preg_split 拆分。
<?php
$email = "user@example.com";
if (preg_match("/^[\w.-]+@[\w.-]+\.\w+$/", $email)) {
echo "邮箱格式正确\n";
} else {
echo "邮箱格式错误\n";
}
$text = "订单号 123,金额 45.6 元";
echo preg_replace("/\d+/", "#", $text) . "\n";
$csv = "php,go|rust;elixir";
$langs = preg_split("/[,|;]/", $csv);
print_r($langs);
?>
实训7.4 格式化输出
用 printf/sprintf 格式化浮点、补零、科学计数法输出。
printf 直接输出;sprintf 返回字符串;%d/%f/%s/%05d 常用占位符。
<?php
$pi = 3.1415926;
printf("保留两位:%.2f\n", $pi);
printf("补零五位:%05d\n", 42);
printf("左对齐:%-8s|\n", "PHP");
$formatted = sprintf("价格:¥%.2f", 59.9);
echo $formatted . "\n";
?>
单元8 · 面向对象
类、属性方法、继承、封装、接口
- 类:class + public/private 属性方法。
- 继承:extends + parent:: + 方法重写。
- 接口:interface + implements + 多态。
实训8.1 定义类与对象
定义 Student 类(name、score 属性,getInfo 方法),实例化并调用。
class 定义类;public 属性与方法;new 实例化;-> 访问成员。
<?php
class Student {
public $name;
public $score;
public function __construct($name, $score) {
$this->name = $name;
$this->score = $score;
}
public function getInfo() {
return "{$this->name},成绩 {$this->score} 分";
}
}
$stu = new Student("小明", 92.5);
echo $stu->getInfo() . "\n";
?>
实训8.2 继承与方法重写
定义 Animal 基类和 Dog 子类,子类重写 speak 方法并调用父类构造。
extends 继承;parent:: 调用父类方法;子类可重写方法。
<?php
class Animal {
protected $name;
public function __construct($name) {
$this->name = $name;
}
public function speak() {
return "动物叫声";
}
}
class Dog extends Animal {
public function speak() {
return parent::speak() . ":汪汪!";
}
}
$dog = new Dog("旺财");
echo $dog->speak() . "\n";
?>
实训8.3 封装与访问控制
用 private 属性 + getter/setter 实现银行账户的封装。
private 私有属性外部不可直接访问;通过公有方法读写并校验。
<?php
class BankAccount {
private float $balance = 0;
public function deposit(float $amount): void {
if ($amount > 0) {
$this->balance += $amount;
}
}
public function withdraw(float $amount): bool {
if ($amount > 0 && $amount <= $this->balance) {
$this->balance -= $amount;
return true;
}
return false;
}
public function getBalance(): float {
return $this->balance;
}
}
$acc = new BankAccount();
$acc->deposit(1000);
$acc->withdraw(300);
echo "余额:" . $acc->getBalance() . "\n";
?>
实训8.4 接口与多态
定义 Shape 接口(area 方法),Circle 与 Square 实现,遍历计算总面积。
interface 定义契约;implements 实现;多态统一调用。
<?php
interface Shape {
public function area(): float;
}
class Circle implements Shape {
public function __construct(private float $radius) {}
public function area(): float {
return 3.14159 * $this->radius ** 2;
}
}
class Square implements Shape {
public function __construct(private float $side) {}
public function area(): float {
return $this->side ** 2;
}
}
$shapes = [new Circle(3), new Square(5)];
$total = 0;
foreach ($shapes as $shape) {
$total += $shape->area();
}
printf("总面积:%.2f\n", $total);
?>
单元9 · 超全局变量与表单
$_GET/$_POST/$_SERVER、表单处理、session
- 超全局:$_GET/$_POST/$_SERVER/$_FILES/$_SESSION。
- 安全:htmlspecialchars 转义输出防 XSS。
- 会话:session_start + $_SESSION 管理登录态。
实训9.1 $_GET 查询参数
模拟接收 /greet.php?name=Alice&lang=zh 的 GET 参数并输出问候。
$_GET 数组保存 URL 查询参数;isset/empty 判断存在性。
<?php
$name = $_GET["name"] ?? "游客";
$lang = $_GET["lang"] ?? "zh";
if ($lang === "zh") {
echo "你好,$name!\n";
} else {
echo "Hello, $name!\n";
}
?>
实训9.2 $_POST 表单处理
处理 POST 提交的用户名与密码,输出提交内容并校验非空。
$_POST 保存 POST 请求体;htmlspecialchars 防 XSS 转义输出。
<?php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$username = htmlspecialchars($_POST["username"] ?? "");
$password = $_POST["password"] ?? "";
if ($username === "" || $password === "") {
echo "用户名和密码不能为空\n";
} else {
echo "欢迎,$username!密码长度:" . strlen($password) . "\n";
}
} else {
echo "请使用 POST 提交表单\n";
}
?>
实训9.3 Session 会话管理
启动 session,存储用户登录状态,跨请求读取并销毁。
session_start() 启动;$_SESSION 存取值;session_destroy 销毁。
<?php
session_start();
$_SESSION["user_id"] = 1;
$_SESSION["username"] = "admin";
echo "已写入 Session\n";
echo "当前用户:" . ($_SESSION["username"] ?? "未登录") . "\n";
unset($_SESSION["username"]);
echo "注销后:" . ($_SESSION["username"] ?? "未登录") . "\n";
session_destroy();
?>
实训9.4 文件上传处理
接收 $_FILES 上传的文件,校验类型与大小并移动到上传目录。
$_FILES['field'] 含 name/tmp_name/size/error;move_uploaded_file 移动。
<?php
// 模拟表单:<input type="file" name="avatar">
if (isset($_FILES["avatar"])) {
$file = $_FILES["avatar"];
if ($file["error"] !== UPLOAD_ERR_OK) {
echo "上传失败,错误码:" . $file["error"] . "\n";
} elseif ($file["size"] > 2 * 1024 * 1024) {
echo "文件超过 2MB\n";
} else {
$ext = strtolower(pathinfo($file["name"], PATHINFO_EXTENSION));
if (!in_array($ext, ["jpg", "png", "gif"])) {
echo "仅支持 jpg/png/gif\n";
} else {
$dest = "uploads/" . uniqid() . "." . $ext;
move_uploaded_file($file["tmp_name"], $dest);
echo "上传成功:" . $dest . "\n";
}
}
}
?>
单元10 · 文件与目录操作
文件读写、目录遍历、JSON 数据处理
- 文件:file_put_contents/file_get_contents/filesize。
- 目录:scandir/is_file/mkdir 遍历目录。
- 数据:json_encode/json_decode;fputcsv/fgetcsv。
实训10.1 文件写入与读取
用 file_put_contents 写入数据文件,用 file_get_contents 读取输出。
file_put_contents 写入;file_get_contents 读取整个文件。
<?php
$file = "data.txt";
file_put_contents($file, "Hello PHP File System\n第二行");
$content = file_get_contents($file);
echo "文件内容:\n" . $content;
echo "文件大小:" . filesize($file) . " 字节\n";
?>
实训10.2 目录遍历
读取指定目录下所有文件,输出文件名与大小,统计文件总数。
scandir 列出目录;is_file 判断;filesize 取大小。
<?php
$dir = "docs";
if (!is_dir($dir)) {
mkdir($dir);
file_put_contents("$dir/a.txt", "A");
file_put_contents("$dir/b.txt", "B");
}
$items = scandir($dir);
$count = 0;
foreach ($items as $item) {
if ($item === "." || $item === "..") {
continue;
}
$path = "$dir/$item";
if (is_file($path)) {
echo "$item:" . filesize($path) . " 字节\n";
$count++;
}
}
echo "文件总数:$count\n";
?>
实训10.3 JSON 数据处理
用 json_encode 序列化数组,用 json_decode 解析并读取字段。
json_encode 转 JSON;json_decode 第二个参数 true 得到关联数组。
<?php
$user = [
"id" => 1,
"name" => "Alice",
"tags" => ["admin", "dev"],
];
$json = json_encode($user, JSON_UNESCAPED_UNICODE);
echo "JSON:" . $json . "\n";
$back = json_decode($json, true);
echo "姓名:" . $back["name"] . "\n";
echo "标签数:" . count($back["tags"]) . "\n";
echo "JSON 错误:" . json_last_error_msg() . "\n";
?>
实训10.4 CSV 读写
把学生数组写入 CSV 文件,再读取 CSV 并解析为数组输出。
fputcsv 写入行;fgetcsv 读取行;fopen/fclose 管理句柄。
<?php
$students = [
["张三", 90],
["李四", 85],
["王五", 78],
];
$handle = fopen("students.csv", "w");
foreach ($students as $row) {
fputcsv($handle, $row);
}
fclose($handle);
$handle = fopen("students.csv", "r");
echo "CSV 内容:\n";
while (($row = fgetcsv($handle)) !== false) {
echo $row[0] . ":" . $row[1] . " 分\n";
}
fclose($handle);
?>
单元11 · MySQL 与 PDO 基础
PDO 连接、预处理语句、增删改查
- PDO:new PDO + 错误模式 + try/catch。
- 预处理:prepare + execute 防 SQL 注入。
- 结果:fetchAll(PDO::FETCH_ASSOC) 获取行。
实训11.1 PDO 连接数据库
用 PDO 连接 MySQL,设置错误模式并执行简单查询。
new PDO(dsn, user, pass);setAttribute 设置错误模式;query 查询。
<?php
try {
$pdo = new PDO(
"mysql:host=localhost;dbname=test;charset=utf8mb4",
"root",
"password",
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
echo "数据库连接成功\n";
$version = $pdo->query("SELECT VERSION()")->fetchColumn();
echo "MySQL 版本:" . $version . "\n";
} catch (PDOException $e) {
echo "连接失败:" . $e->getMessage() . "\n";
}
?>
实训11.2 预处理语句插入
用预处理语句向 users 表插入用户,防止 SQL 注入。
prepare + execute 参数绑定;? 占位符或命名参数 :name。
<?php
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", "root", "password");
$sql = "INSERT INTO users (name, email) VALUES (?, ?)";
$stmt = $pdo->prepare($sql);
$users = [
["Alice", "alice@example.com"],
["Bob", "bob@example.com"],
];
foreach ($users as $user) {
$stmt->execute($user);
echo "插入成功,ID:" . $pdo->lastInsertId() . "\n";
}
?>
实训11.3 查询与遍历结果
查询 users 表所有用户,用 fetchAll 获取并遍历输出。
query 或 prepare+execute 执行 SELECT;fetchAll 获取全部行。
<?php
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", "root", "password");
$stmt = $pdo->query("SELECT id, name, email FROM users ORDER BY id");
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo "共 " . count($users) . " 个用户:\n";
foreach ($users as $user) {
echo "#{$user['id']} {$user['name']} ({$user['email']})\n";
}
?>
实训11.4 更新与删除数据
用预处理语句按 ID 更新用户邮箱,再删除指定用户。
UPDATE/DELETE 同样走 prepare + execute 绑定参数。
<?php
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", "root", "password");
$update = $pdo->prepare("UPDATE users SET email = ? WHERE id = ?");
$update->execute(["new@example.com", 1]);
echo "更新行数:" . $update->rowCount() . "\n";
$delete = $pdo->prepare("DELETE FROM users WHERE id = ?");
$delete->execute([2]);
echo "删除行数:" . $delete->rowCount() . "\n";
?>
单元12 · 综合项目实训
综合运用 PHP 知识完成项目
- 综合:数组、函数、面向对象、文件、JSON 组合。
- 校验:输入校验与错误收集贯穿项目。
实训12.1 简易留言板(数组版)
用数组模拟留言板:支持添加留言、列出留言、按时间倒序输出。
关联数组存储留言;array_unshift 新留言置顶;遍历输出。
<?php
$messages = [];
function addMessage(&$messages, $author, $content) {
array_unshift($messages, [
"author" => $author,
"content" => $content,
"time" => date("Y-m-d H:i:s"),
]);
}
function listMessages($messages) {
if (count($messages) === 0) {
echo "暂无留言\n";
return;
}
foreach ($messages as $msg) {
echo "[{$msg['time']}] {$msg['author']}:{$msg['content']}\n";
}
}
addMessage($messages, "小明", "第一条留言");
addMessage($messages, "小红", "PHP 真好学");
listMessages($messages);
?>
实训12.2 用户注册数据校验
编写函数校验注册数据:用户名 3-20 位、密码至少 8 位且含数字、邮箱格式正确。
strlen/preg_match 校验;返回错误数组;逐项检查。
<?php
function validateRegister(array $data): array {
$errors = [];
$username = $data["username"] ?? "";
$password = $data["password"] ?? "";
$email = $data["email"] ?? "";
if (strlen($username) < 3 || strlen($username) > 20) {
$errors[] = "用户名长度需在 3-20 之间";
}
if (strlen($password) < 8 || !preg_match("/\d/", $password)) {
$errors[] = "密码至少 8 位且包含数字";
}
if (!preg_match("/^[\w.-]+@[\w.-]+\.\w+$/", $email)) {
$errors[] = "邮箱格式不正确";
}
return $errors;
}
$data = ["username" => "ab", "password" => "abc12345", "email" => "bad"];
$errors = validateRegister($data);
echo empty($errors) ? "校验通过\n" : implode(";", $errors) . "\n";
?>
实训12.3 面向对象商品购物车
用类实现购物车:商品添加、数量修改、计算总价、输出清单。
Cart 类维护 items 数组;add/update/total 方法;foreach 输出。
<?php
class CartItem {
public function __construct(
public string $name,
public float $price,
public int $qty = 1
) {}
public function subtotal(): float {
return $this->price * $this->qty;
}
}
class Cart {
private array $items = [];
public function add(CartItem $item): void {
$this->items[] = $item;
}
public function total(): float {
$sum = 0;
foreach ($this->items as $item) {
$sum += $item->subtotal();
}
return $sum;
}
public function list(): void {
foreach ($this->items as $item) {
printf("%s x%d = %.2f 元\n", $item->name, $item->qty, $item->subtotal());
}
}
}
$cart = new Cart();
$cart->add(new CartItem("PHP 教程", 59, 2));
$cart->add(new CartItem("编程鼠标", 129, 1));
$cart->list();
printf("总计:%.2f 元\n", $cart->total());
?>
实训12.4 文件存储的任务清单
把任务清单序列化为 JSON 存储到文件:添加任务、保存、读取并列出未完成任务。
json_encode 保存到文件;json_decode 读回;array_filter 过滤未完成。
<?php
$file = "tasks.json";
function loadTasks(string $file): array {
if (!file_exists($file)) {
return [];
}
return json_decode(file_get_contents($file), true) ?? [];
}
function saveTasks(string $file, array $tasks): void {
file_put_contents($file, json_encode($tasks, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
}
$tasks = loadTasks($file);
$tasks[] = ["id" => count($tasks) + 1, "title" => "学习 PHP 面向对象", "done" => false];
$tasks[] = ["id" => count($tasks) + 1, "title" => "练习 PDO 操作", "done" => false];
saveTasks($file, $tasks);
$pending = array_filter($tasks, fn($t) => !$t["done"]);
echo "未完成任务:\n";
foreach ($pending as $task) {
echo "- [{$task['id']}] {$task['title']}\n";
}
?>