1.PHP 8 概述与环境搭建
一、PHP 8 核心概述
1.1 PHP 是什么?
PHP 全称:Hypertext Preprocessor(超文本预处理器),注意这是一个递归缩写,最初是 Personal Home Page Tools 的缩写,后改为现在的官方全称。
PHP(Hypertext Preprocessor,超文本预处理器)是一门开源的服务器端脚本语言,专门用于 Web 开发:
- 核心定位:嵌入 HTML 中执行,负责处理服务端逻辑(如数据库交互、用户登录验证、数据计算等)。
- 应用场景:网站开发(博客 / 电商 / 管理系统)、CLI 脚本(定时任务 / 数据处理)、API 接口开发。
- 生态优势:语法简单易上手、开源免费、丰富的扩展库(MySQL/Redis/ 图像处理等)、跨平台(Windows/Linux/Mac)。
1.2 PHP 8 的核心改进(重点)
PHP 8 是 PHP 语言的里程碑版本,相比 7.x 系列,主要提升集中在 性能、类型安全、语法简化 三大方向:
表格
| 改进方向 | 核心特性 | 价值 |
|---|---|---|
| 性能提升 | JIT 编译器(Just-In-Time)、底层算法优化 | CPU 密集型任务性能提升 20%-30%,Web 场景性能提升约 10% |
| 类型安全增强 | 联合类型、混合类型、never 类型、严格类型模式 | 减少运行时错误,代码可读性 / 可维护性提升,适配大型项目开发 |
| 语法简化 | 命名参数、match 表达式、空安全运算符、构造函数属性提升 | 代码量减少,写法更简洁直观 |
| 错误处理优化 | 致命错误转为异常、异常链支持 | 错误捕获更全面,程序稳定性提升 |
| 废弃特性 | 移除 ereg 扩展、$HTTP_RAW_POST_DATA 等过时特性 | 简化语言核心,减少历史包袱 |
1.3 PHP 8.x 版本演进
- 8.0(2020.11):核心新特性(JIT、联合类型、match 等)的首次发布。
- 8.1(2021.11):新增枚举(Enum)、只读属性、纤程(Fiber)等。
- 8.2(2022.12):新增 Disjunctive Normal Form 类型、弃用动态属性等。
- 8.3(2023.11):新增类型化常量、数组解包优化、json_validate () 函数等。
- 学习建议:优先掌握 8.0-8.1 的核心特性,8.2+ 特性按需学习。
二、PHP 8 环境搭建
2.1 环境选择(新手友好 + 生产级)
方案 1:一键集成环境(新手首选)
- Windows:XAMPP、WAMP、PhpStudy(集成 Apache/Nginx + PHP + MySQL,一键启动)。
- Mac:MAMP、XAMPP for Mac。
- 优势:无需手动配置,5 分钟搞定,自带管理面板,适合入门学习。
方案 2:Docker 容器(生产级推荐)
- 优势:环境隔离、版本灵活切换、与生产环境一致,避免「本地能跑,服务器报错」。
- 前提:先安装 Docker Desktop(Windows/Mac 直接下载安装包,Linux 按官方教程)。
2.2 实操步骤(分方案讲解)
方案 1:XAMPP 搭建 PHP 8 环境(Windows 示例)
-
下载安装包
- 官网:https://www.apachefriends.org/
- 选择对应系统版本,确保下载的包包含 PHP 8.x(如 XAMPP 8.2.0 及以上)。
-
安装与配置
- 双击安装包,一路「Next」(建议安装路径选非中文目录,如
D:\xampp)。 - 安装完成后,打开 XAMPP Control Panel,启动 Apache 和 MySQL(端口默认 80/3306,若端口被占用可修改)。
- 双击安装包,一路「Next」(建议安装路径选非中文目录,如
-
验证环境
- 打开浏览器,访问
http://localhost或http://127.0.0.1,能看到 XAMPP 欢迎页即 Apache 正常。 - 在 XAMPP 的
htdocs目录(如D:\xampp\htdocs)新建文件info.php,内容如下:
php<?php // 输出 PHP 环境信息,重点看 PHP 版本 phpinfo(); ?>- 访问
http://localhost/info.php,页面中能看到「PHP Version 8.x.x」即 PHP 8 环境搭建成功。
- 打开浏览器,访问
方案 2:Docker 搭建 PHP 8 环境(通用)
-
编写 docker-compose.yml 在本地新建文件夹(如
php8-learn),创建docker-compose.yml文件,内容如下:yaml
version: '3.8' services: # PHP + Nginx 容器 web: image: php:8.1-fpm-nginx ports: - "8080:80" # 本地 8080 端口映射到容器 80 端口 volumes: # 本地代码目录映射到容器的网站根目录 - ./www:/var/www/html restart: always # MySQL 容器(可选,用于数据库操作) mysql: image: mysql:8.0 ports: - "3306:3306" environment: - MYSQL_ROOT_PASSWORD=123456 # root 密码 - MYSQL_DATABASE=php8_demo # 初始化数据库 volumes: - ./mysql-data:/var/lib/mysql restart: always -
启动容器
-
打开终端(Windows 用 PowerShell,Mac/Linux 用终端),进入
docker-compose.yml所在目录。 -
执行命令启动容器:
docker-compose up -d
-
-
验证环境
- 在
php8-learn目录下新建www文件夹,创建info.php(内容同方案 1)。 - 访问
http://localhost:8080/info.php,能看到 PHP 8.1 版本信息即环境成功。
- 在
2.3 开发工具配置
推荐工具:VS Code(免费)
- 安装 VS Code:官网 https://code.visualstudio.com/。
- 安装必备插件:
- PHP Intelephense(代码提示、语法检查)。
- PHP Debug(配合 Xdebug 调试)。
- EditorConfig for VS Code(统一代码格式)。
- 配置 PHP 路径(可选):
- 打开 VS Code 设置,搜索「PHP Path」,填写 PHP 可执行文件路径(如 XAMPP 的
D:\xampp\php\php.exe)。
- 打开 VS Code 设置,搜索「PHP Path」,填写 PHP 可执行文件路径(如 XAMPP 的
备选工具:PhpStorm(付费,功能更强)
- 官网:https://www.jetbrains.com/phpstorm/
- 自带 PHP 语法检查、调试、框架支持,无需额外配置,适合专业开发。
三、环境验证与常见问题解决
3.1 核心验证点
- 执行
php -v命令(XAMPP 需进入php目录,Docker 需进入容器),输出 PHP 8.x 版本。 - 访问
info.php确认 PHP 版本、扩展(如 mysqli、PDO)是否正常加载。
3.2 常见问题
- Apache 启动失败:大概率是 80 端口被占用(如 IIS、微信开发工具),可在 XAMPP 面板修改 Apache 端口(如改为 8080)。
- PHP 扩展未加载 :在
php.ini中取消对应扩展注释(如extension=mysqli),重启 Apache/PHP-FPM。 - Docker 容器启动失败 :检查端口是否被占用,或删除旧容器后重新启动(
docker-compose down && docker-compose up -d)。
2.PHP 基本语法规则
1.1 PHP 代码的执行边界
PHP 是嵌入式脚本语言,代码需用 <?php ?> 标记包裹(短标签 <? ?> 不推荐,需配置开启,兼容性差):
php
<?php
// 这是 PHP 代码区域
echo "Hello PHP 8!"; // 输出内容到浏览器/控制台
?>
<!-- HTML 与 PHP 混合示例 -->
<p>当前时间:<?php echo date('Y-m-d H:i:s'); ?></p>
- 关键说明 :
- PHP 文件后缀通常为
.php; - 代码末尾的
?>在纯 PHP 文件中可省略(推荐),避免多余空格导致 header 报错; - PHP 代码区分大小写(变量名敏感,关键字 / 函数名不敏感)
- PHP 文件后缀通常为
php
<?php
$name = "PHP";
echo $Name; // 未定义,输出空(变量名区分大小写)
ECHO $name; // 正常输出 "PHP"(echo 关键字不区分大小写)
1.2 注释规则
注释不执行,用于解释代码,分两种类型:
php
<?php
// 单行注释(推荐,简洁)
# 单行注释(兼容 shell 风格,少用)
/*
多行注释
适合大段说明
注意:多行注释不能嵌套
*/
echo "注释不影响代码执行";
1.3 语句结束符
PHP 语句必须以分号 ; 结尾(最后一条语句的分号可省略,但推荐统一添加,避免后续追加代码出错):
php
<?php
$a = 10; // 变量赋值,分号结尾
$b = 20;
echo $a + $b; // 输出 30,分号结尾
1.4 变量规则
变量是存储数据的容器,PHP 变量有明确的语法规则:
(1)定义规则
- 以
$开头,后跟字母 / 下划线,再跟字母 / 数字 / 下划线; - 不能以数字开头,不能包含特殊字符(如
-、@); - 区分大小写(
$name≠$Name)。
php
<?php
$username = "张三"; // 合法
$age = 25; // 合法
$_score = 95.5; // 合法
// $123abc = 100; // 非法(以数字开头)
// $user-name = "李四"; // 非法(包含减号)
(2)数据类型
PHP 是弱类型语言(变量类型由赋值决定),核心类型如下:
| 类型分类 | 具体类型 | 示例 | PHP 8 补充 |
|---|---|---|---|
| 标量类型 | 字符串(string) | $str = "PHP8" |
支持原生字符串(<<<EOD) |
| 整数(int) | $num = 100 |
支持二进制(0b1010) |
|
| 浮点数(float) | $price = 99.9 |
精度问题需注意 | |
| 布尔值(bool) | $is_ok = true |
true/false 不区分大小写 |
|
| 复合类型 | 数组(array) | $arr = [1,2,3] |
短数组语法([])推荐 |
| 对象(object) | $obj = new stdClass |
PHP 8 枚举(Enum)归为此类 | |
| 特殊类型 | 空值(null) | $n = null |
仅 null 一个值 |
| 资源(resource) | 数据库连接、文件句柄 | 现代 PHP 逐渐弱化 |
(3)常量规则
常量是一旦定义就不可修改的量,PHP 8 支持多种定义方式:
php
<?php
// 传统方式(全局常量)
define("PI", 3.14159);
echo PI; // 输出 3.14159
// 类内常量(PHP 5.3+)
class Math {
const MAX = 100;
// PHP 8.2+ 类型化常量
const int MIN = 0;
}
echo Math::MAX; // 输出 100
// PHP 8.1+ 枚举(特殊常量)
enum Status {
case SUCCESS;
case FAILED;
}
echo Status::SUCCESS->name; // 输出 SUCCESS
1.5 运算符与流程控制
(1)常用运算符
| 类型 | 示例 | 说明 |
|---|---|---|
| 算术运算符 | +、-、*、/、% |
加减乘除、取余 |
| 赋值运算符 | =、+=、*= |
$a += 5 等价于 $a = $a+5 |
| 比较运算符 | ==(值相等)、===(全等) |
0 == "0" 为 true,0 === "0" 为 false |
| 逻辑运算符 | &&、|| 、! |
与、或、非 |
(2)流程控制
核心用于控制代码执行顺序,新手必掌握:
php
<?php
// 1. 条件判断
$score = 85;
if ($score >= 90) {
echo "优秀";
} elseif ($score >= 70) {
echo "良好";
} else {
echo "及格";
}
// PHP 8 match 表达式(替代 switch,更简洁)
$status = 1;
$result = match ($status) {
1 => "成功",
2 => "失败",
3 => "处理中",
default => "未知状态",
};
echo $result; // 输出 "成功"
// 2. 循环
// for 循环
for ($i = 1; $i <= 5; $i++) {
echo $i . " "; // 输出 1 2 3 4 5
}
// foreach 循环(遍历数组)
$fruits = ["苹果", "香蕉", "橙子"];
foreach ($fruits as $index => $fruit) {
echo "索引{$index}:{$fruit} <br>";
}
3.函数基础
函数是封装可复用代码的模块,PHP 函数分为「内置函数」和「自定义函数」。
2.1 函数定义规则
php
<?php
/**
* 自定义函数模板
* @param 类型 $参数名 参数说明
* @return 类型 返回值说明
*/
function 函数名(参数列表) {
// 函数体(要执行的代码)
return 返回值; // 可选,无 return 则返回 null
}
- 核心规则 :
- 函数名以字母 / 下划线开头,不区分大小写(推荐小写 + 下划线命名);
- 参数可指定默认值(默认参数需放在非默认参数后);
- PHP 8 支持「类型提示」(指定参数 / 返回值类型),增强类型安全。
基础示例
php
<?php
// 无参数、无返回值
function sayHello() {
echo "Hello PHP!<br>";
}
sayHello(); // 调用函数,输出 Hello PHP!
// 有参数、有返回值(PHP 8 类型提示)
function add(int $a, int $b): int {
return $a + $b;
}
echo add(5, 3); // 输出 8
// 默认参数
function greet(string $name = "访客"): string {
return "你好,{$name}!";
}
echo greet(); // 输出 你好,访客!
echo greet("张三"); // 输出 你好,张三!
// PHP 8 命名参数(调用时指定参数名,无需按顺序)
echo greet(name: "李四"); // 输出 你好,李四!
2.2 变量作用域
变量的作用域指变量可被访问的范围,核心分为 3 类:
php
<?php
$global_var = "全局变量"; // 全局变量(函数外定义)
function testScope() {
$local_var = "局部变量"; // 局部变量(函数内定义,外部不可访问)
echo $local_var . "<br>"; // 正常输出
// 访问全局变量:需用 global 关键字或 $GLOBALS 数组
global $global_var;
echo $global_var . "<br>"; // 正常输出
// 静态变量(函数执行后保留值)
static $count = 0;
$count++;
echo "计数:{$count}<br>";
}
testScope(); // 输出 局部变量 + 全局变量 + 计数:1
testScope(); // 输出 局部变量 + 全局变量 + 计数:2(静态变量保留了 1)
// echo $local_var; // 报错:未定义变量(局部变量外部不可访问)
2.3 内置函数使用
PHP 内置了数千个函数,覆盖字符串、数组、文件等场景,无需定义可直接调用:
(1)字符串函数
php
<?php
$str = "PHP 8 基础语法";
echo strlen($str); // 输出 8(字符串长度)
echo strtoupper($str); // 输出 PHP 8 基础语法(转大写)
echo str_replace("8", "八", $str); // 输出 PHP 八 基础语法(替换)
(2)数组函数
php
<?php
$arr = [3, 1, 2];
sort($arr); // 升序排序
print_r($arr); // 输出 Array ( [0] => 1 [1] => 2 [2] => 3 )
echo count($arr); // 输出 3(数组长度)
echo in_array(2, $arr); // 输出 1(true,判断元素是否存在)
(3)PHP 8 新增内置函数
php
<?php
// json_validate()(PHP 8.3+):验证 JSON 字符串是否合法
$json = '{"name":"PHP8"}';
var_dump(json_validate($json)); // 输出 bool(true)
// str_contains()(PHP 8.0+):判断字符串是否包含子串
var_dump(str_contains("PHP8", "8")); // 输出 bool(true)
2.4 函数进阶(PHP 8 特性)
(1)联合类型参数
允许参数接收多种类型的值:
<?php
// PHP 8 联合类型:参数可以是 int 或 string
function showValue(int|string $value): void {
echo "值:{$value}<br>";
}
showValue(100); // 输出 值:100
showValue("PHP"); // 输出 值:PHP
(2)Never 类型返回值
表示函数永不返回(如抛异常、死循环):
<?php
function error(string $msg): never {
echo "错误:{$msg}";
exit; // 终止程序,永不返回
}
// error("参数错误"); // 执行后程序终止
练习:
编写一个 PHP 8 程序,实现以下核心功能:
- 定义函数
calculateScore(array $scores): array,接收学生单科成绩数组(支持整数 / 浮点数); - 过滤数组中非数值类型的成绩(如字符串、布尔值等无效数据);
- 计算有效成绩的平均分(保留 1 位小数);
- 使用 PHP 8 的
match表达式根据平均分判断成绩等级:- 90 分及以上:优秀
- 80-89 分:良好
- 60-79 分:及格
- 60 分以下:不及格
- 函数返回包含「平均分」「等级」「有效成绩数量」的关联数组。
php
<?php
/**
* 实战:计算学生平均分,判断等级
* 涵盖变量、数组、循环、函数、PHP 8 类型提示
*/
function calculateScore(array $scores): array {
$total = 0;
$count = count($scores);
// 遍历计算总分
foreach ($scores as $score) {
// 过滤非数值类型(PHP 8 类型提示仅在严格模式生效)
if (!is_numeric($score)) {
continue;
}
$total += $score;
}
// 计算平均分
$average = $count > 0 ? $total / $count : 0;
// 判断等级(PHP 8 match 表达式)
$level = match (true) {
$average >= 90 => "优秀",
$average >= 80 => "良好",
$average >= 60 => "及格",
default => "不及格",
};
return [
"平均分" => round($average, 1), // 保留 1 位小数
"等级" => $level
];
}
// 调用函数
$studentScores = [85, 92, 78, 90];
$result = calculateScore($studentScores);
// 输出结果
echo "学生成绩分析:<br>";
echo "平均分:{$result['平均分']}<br>";
echo "等级:{$result['等级']}<br>";
// 输出:平均分:86.2,等级:良好
4.PHP 8 MySQL数据库操作
一、核心知识点概述
PHP 操作 MySQL 数据库的主流方式有两种,均适配 PHP 8:
表格
| 方式 | 特点 | 适用场景 |
|---|---|---|
| MySQLi | 仅支持 MySQL,分面向过程 / 面向对象写法,PHP 8 优化了错误处理 | 仅使用 MySQL 的简单项目 |
| PDO | 支持多数据库(MySQL/Oracle/PostgreSQL 等),仅面向对象,安全性更高 | 跨数据库项目、企业级开发 |
核心原则:无论使用哪种方式,都必须使用「预处理语句」防止 SQL 注入,这是 Web 开发的基础安全要求。
二、环境准备
- 确保 PHP 环境已启用相关扩展:
- MySQLi 扩展:
extension=mysqli(php.ini 中取消注释,PHP 8 默认启用); - PDO 扩展:
extension=pdo_mysql(php.ini 中取消注释)。
- MySQLi 扩展:
- 验证扩展是否启用:创建
phpinfo.php,查看mysqli和PDO模块是否存在。 - 准备测试数据库 / 表:
sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS php8_demo DEFAULT CHARSET utf8mb4;
USE php8_demo;
-- 创建学生表
CREATE TABLE IF NOT EXISTS students (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
name VARCHAR(50) NOT NULL COMMENT '姓名',
age TINYINT UNSIGNED NOT NULL COMMENT '年龄',
score FLOAT NOT NULL COMMENT '成绩',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) COMMENT '学生信息表';
三、MySQLi 面向对象操作(PHP 8 版)
3.1 数据库连接
php
<?php
/**
* MySQLi 连接数据库(PHP 8 错误处理)
* @return mysqli 数据库连接对象
*/
function connectMysql(): mysqli {
// 数据库配置(建议抽离到配置文件)
$host = 'localhost';
$user = 'root';
$password = '123456';
$dbname = 'php8_demo';
$charset = 'utf8mb4';
// 建立连接(PHP 8 支持严格类型,连接失败抛出 Error 异常)
try {
$mysqli = new mysqli($host, $user, $password, $dbname);
// 检查连接错误
if ($mysqli->connect_errno) {
throw new Exception("数据库连接失败:{$mysqli->connect_error}");
}
// 设置字符集
$mysqli->set_charset($charset);
return $mysqli;
} catch (Exception $e) {
die("错误:{$e->getMessage()}");
}
}
// 测试连接
$mysqli = connectMysql();
echo "MySQLi 数据库连接成功!<br>";
3.2 CRUD 核心操作(预处理语句)
(1)新增数据(CREATE)
php
<?php
// 1. 连接数据库
$mysqli = connectMysql();
// 2. 准备预处理语句(? 是占位符)
$sql = "INSERT INTO students (name, age, score) VALUES (?, ?, ?)";
$stmt = $mysqli->prepare($sql);
// 3. 绑定参数(s=字符串,i=整数,d=浮点数)
$name = "张三";
$age = 18;
$score = 92.5;
// PHP 8 支持类型提示,绑定参数时自动匹配类型
$stmt->bind_param("sid", $name, $age, $score);
// 4. 执行语句
if ($stmt->execute()) {
echo "新增成功,自增ID:{$mysqli->insert_id}<br>";
} else {
echo "新增失败:{$stmt->error}<br>";
}
// 5. 关闭资源
$stmt->close();
$mysqli->close();
(2)查询数据(READ)
php
<?php
// 1. 连接数据库
$mysqli = connectMysql();
// 2. 准备预处理语句(查询年龄≥18的学生)
$sql = "SELECT id, name, age, score FROM students WHERE age >= ?";
$stmt = $mysqli->prepare($sql);
// 3. 绑定参数并执行
$minAge = 18;
$stmt->bind_param("i", $minAge);
$stmt->execute();
// 4. 绑定结果集(将查询结果绑定到变量)
$stmt->bind_result($id, $name, $age, $score);
// 5. 遍历结果
echo "<h3>学生列表(年龄≥18)</h3>";
echo "<ul>";
while ($stmt->fetch()) {
echo "<li>ID:{$id},姓名:{$name},年龄:{$age},成绩:{$score}</li>";
}
echo "</ul>";
// 6. 关闭资源
$stmt->close();
$mysqli->close();
(3)更新数据(UPDATE)
php
<?php
// 1. 连接数据库
$mysqli = connectMysql();
// 2. 准备预处理语句(更新ID=1的学生成绩)
$sql = "UPDATE students SET score = ? WHERE id = ?";
$stmt = $mysqli->prepare($sql);
// 3. 绑定参数并执行
$newScore = 95.0;
$id = 1;
$stmt->bind_param("di", $newScore, $id);
if ($stmt->execute()) {
echo "更新成功,影响行数:{$stmt->affected_rows}<br>";
} else {
echo "更新失败:{$stmt->error}<br>";
}
// 4. 关闭资源
$stmt->close();
$mysqli->close();
(4)删除数据(DELETE)
php
<?php
// 1. 连接数据库
$mysqli = connectMysql();
// 2. 准备预处理语句(删除ID=1的学生)
$sql = "DELETE FROM students WHERE id = ?";
$stmt = $mysqli->prepare($sql);
// 3. 绑定参数并执行
$id = 1;
$stmt->bind_param("i", $id);
if ($stmt->execute()) {
echo "删除成功,影响行数:{$stmt->affected_rows}<br>";
} else {
echo "删除失败:{$stmt->error}<br>";
}
// 4. 关闭资源
$stmt->close();
$mysqli->close();
四、PDO 操作(PHP 8 推荐)
PDO 是 PHP 数据对象(PHP Data Objects),支持多数据库,是 PHP 8 企业级开发的首选方式。
4.1 数据库连接
php
<?php
/**
* PDO 连接数据库(PHP 8 异常处理)
* @return PDO 数据库连接对象
*/
function connectPdo(): PDO {
// 数据库配置
$dsn = 'mysql:host=localhost;dbname=php8_demo;charset=utf8mb4';
$user = 'root';
$password = '123456';
// PDO 选项(关键:启用异常模式、关闭模拟预处理)
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // PHP 8 推荐异常模式
PDO::ATTR_EMULATE_PREPARES => false, // 禁用模拟预处理,使用数据库原生预处理
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC // 默认关联数组返回结果
];
try {
$pdo = new PDO($dsn, $user, $password, $options);
return $pdo;
} catch (PDOException $e) {
die("PDO 连接失败:{$e->getMessage()}");
}
}
// 测试连接
$pdo = connectPdo();
echo "PDO 数据库连接成功!<br>";
4.2 CRUD 核心操作(预处理语句)
(1)新增数据(CREATE)
php
<?php
// 1. 连接数据库
$pdo = connectPdo();
// 2. 准备预处理语句(命名占位符 :name 更易读)
$sql = "INSERT INTO students (name, age, score) VALUES (:name, :age, :score)";
$stmt = $pdo->prepare($sql);
// 3. 绑定参数并执行(PHP 8 支持数组直接传参)
$params = [
':name' => '李四',
':age' => 19,
':score' => 88.5
];
if ($stmt->execute($params)) {
// 获取自增ID(PHP 8 兼容)
$lastId = $pdo->lastInsertId();
echo "新增成功,自增ID:{$lastId}<br>";
}
// 4. 关闭语句(可选,PHP 会自动回收)
$stmt->closeCursor();
(2)查询数据(READ)
php
<?php
// 1. 连接数据库
$pdo = connectPdo();
// 2. 准备预处理语句(查询成绩≥80的学生)
$sql = "SELECT id, name, age, score FROM students WHERE score >= :min_score";
$stmt = $pdo->prepare($sql);
// 3. 执行语句
$stmt->execute([':min_score' => 80]);
// 4. 获取结果(3种方式)
// 方式1:获取单条
// $student = $stmt->fetch();
// 方式2:获取所有(推荐)
$students = $stmt->fetchAll();
// 方式3:遍历
// while ($student = $stmt->fetch()) {}
// 输出结果
echo "<h3>成绩≥80的学生列表</h3>";
echo "<ul>";
foreach ($students as $stu) {
echo "<li>ID:{$stu['id']},姓名:{$stu['name']},成绩:{$stu['score']}</li>";
}
echo "</ul>";
(3)更新数据(UPDATE)
php
<?php
// 1. 连接数据库
$pdo = connectPdo();
// 2. 准备预处理语句
$sql = "UPDATE students SET age = :age WHERE id = :id";
$stmt = $pdo->prepare($sql);
// 3. 执行语句
$params = [':age' => 20, ':id' => 2];
$stmt->execute($params);
echo "更新成功,影响行数:{$stmt->rowCount()}<br>";
(4)删除数据(DELETE)
php
<?php
// 1. 连接数据库
$pdo = connectPdo();
// 2. 准备预处理语句
$sql = "DELETE FROM students WHERE id = :id";
$stmt = $pdo->prepare($sql);
// 3. 执行语句
$stmt->execute([':id' => 2]);
echo "删除成功,影响行数:{$stmt->rowCount()}<br>";
五、PHP 8 特性优化数据库操作
5.1 类型提示增强
php
<?php
/**
* PHP 8 严格类型:新增学生数据
* @param PDO $pdo 数据库连接对象
* @param string $name 姓名
* @param int $age 年龄
* @param float $score 成绩
* @return int 新增数据的ID
*/
function addStudent(PDO $pdo, string $name, int $age, float $score): int {
$sql = "INSERT INTO students (name, age, score) VALUES (:name, :age, :score)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':name' => $name,
':age' => $age,
':score' => $score
]);
return (int)$pdo->lastInsertId(); // PHP 8 强制类型转换更严格
}
// 调用(类型不匹配会直接报错,提前拦截错误)
$pdo = connectPdo();
$id = addStudent($pdo, "王五", 21, 91.0);
echo "新增学生ID:{$id}<br>";
5.2 联合类型处理空值
php
<?php
/**
* PHP 8 联合类型:根据ID查询学生
* @param PDO $pdo 数据库连接对象
* @param int $id 学生ID
* @return array|null 学生信息(null 表示无数据)
*/
function getStudentById(PDO $pdo, int $id): array|null {
$sql = "SELECT * FROM students WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([':id' => $id]);
return $stmt->fetch() ?: null; // 无数据返回 null
}
// 调用
$student = getStudentById($pdo, 3);
if ($student) {
echo "学生姓名:{$student['name']}<br>";
} else {
echo "未找到该学生<br>";
}
六、核心安全:防止 SQL 注入
为什么预处理语句能防注入?
-
普通拼接 SQL 存在注入风险:
php// 危险!用户输入 `1 OR 1=1` 会查询所有数据 $id = $_GET['id']; $sql = "SELECT * FROM students WHERE id = $id"; -
预处理语句将「SQL 结构」和「数据」分离,数据会被数据库自动转义,杜绝注入:
php// 安全!无论 $id 输入什么,都会被当作普通数据处理 $stmt = $pdo->prepare("SELECT * FROM students WHERE id = :id"); $stmt->execute([':id' => $id]);
七、实战示例:学生成绩管理系统(PDO 版)
php
<?php
// 封装数据库操作类(PHP 8 面向对象)
class StudentManager {
private PDO $pdo; // PHP 8 类属性类型提示
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
// 新增学生
public function add(string $name, int $age, float $score): int {
$sql = "INSERT INTO students (name, age, score) VALUES (:name, :age, :score)";
$stmt = $this->pdo->prepare($sql);
$stmt->execute(compact('name', 'age', 'score'));
return (int)$this->pdo->lastInsertId();
}
// 批量查询
public function list(int $page = 1, int $size = 10): array {
$offset = ($page - 1) * $size;
$sql = "SELECT * FROM students LIMIT :offset, :size";
$stmt = $this->pdo->prepare($sql);
// 数值类型需显式绑定(PDO 对 LIMIT 占位符的特殊处理)
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->bindParam(':size', $size, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll();
}
// 删除学生
public function delete(int $id): bool {
$sql = "DELETE FROM students WHERE id = :id";
$stmt = $this->pdo->prepare($sql);
$stmt->execute(compact('id'));
return $stmt->rowCount() > 0;
}
}
// 调用示例
try {
$pdo = connectPdo();
$manager = new StudentManager($pdo);
// 新增学生
$id = $manager->add("赵六", 22, 85.5);
echo "新增学生ID:{$id}<br>";
// 查询第1页学生(每页10条)
$students = $manager->list();
echo "<h3>学生列表</h3>";
foreach ($students as $stu) {
echo "ID:{$stu['id']},姓名:{$stu['name']},年龄:{$stu['age']}<br>";
}
// 删除学生
$isDeleted = $manager->delete($id);
echo $isDeleted ? "删除成功<br>" : "删除失败<br>";
} catch (PDOException $e) {
echo "操作失败:{$e->getMessage()}";
}
5.PHP 8 Web 开发核心(从请求到响应)
一、Web 开发核心流程概述
PHP 作为服务器端脚本语言,核心作用是处理客户端 HTTP 请求 → 执行服务端逻辑 (如数据库操作、数据计算) → 生成 HTTP 响应(HTML/JSON 等)返回给客户端。
核心流程示意图:

二、HTTP 与 PHP 交互核心
2.1 超全局变量(PHP 8 兼容)
超全局变量是 PHP 预定义的、可在脚本任意位置访问的数组,核心用于接收客户端请求数据:
| 变量名 | 作用 | 安全注意事项 |
|---|---|---|
$_GET |
接收 GET 请求参数(URL 中 ?key=value) |
数据暴露在 URL,不可传敏感信息,需过滤转义 |
$_POST |
接收 POST 请求参数(表单 / JSON 提交) | 适合传敏感信息,仍需过滤验证 |
$_COOKIE |
接收客户端 Cookie 数据 | 可被客户端篡改,仅存储非敏感信息 |
$_SESSION |
接收服务端 Session 数据(基于 Cookie 标识) | 服务端存储,相对安全,需注意 Session 劫持防护 |
$_REQUEST |
包含 $_GET/$_POST/$_COOKIE(PHP 8 已优化默认仅包含 GET/POST) |
不推荐使用,数据来源不明确,易引发安全问题 |
$_SERVER |
服务器 / 请求信息(如请求方法、客户端 IP、URL 等) | 部分字段可被伪造(如 HTTP_X_FORWARDED_FOR),需验证 |
实战示例:获取请求数据(PHP 8 类型安全)
php
<?php
// 开启严格类型(可选,PHP 8 推荐)
declare(strict_types=1);
// 1. 获取 GET 参数(带默认值+类型转换)
$page = $_GET['page'] ?? 1; // PHP 7+ 空合并运算符
$page = (int)$page; // PHP 8 强制类型转换,确保是整数
$keywords = $_GET['keywords'] ?? '';
$keywords = htmlspecialchars($keywords, ENT_QUOTES, 'UTF-8'); // 防 XSS
// 2. 获取 POST 参数(表单提交)
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
// 3. 获取服务器信息
$requestMethod = $_SERVER['REQUEST_METHOD']; // GET/POST/PUT/DELETE 等
$clientIp = $_SERVER['REMOTE_ADDR']; // 客户端 IP(真实IP需结合反向代理处理)
$currentUrl = $_SERVER['PHP_SELF']; // 当前脚本路径
// 输出示例
echo "请求方法:{$requestMethod}<br>";
echo "当前页码:{$page}<br>";
echo "搜索关键词:{$keywords}<br>";
2.2 HTTP 响应控制
PHP 可直接控制 HTTP 响应的状态码、响应头、输出内容,是 Web 开发的核心能力。
(1)设置 HTTP 状态码
php
<?php
// 基础用法:设置 404 页面
http_response_code(404); // PHP 5.4+ 支持,PHP 8 优化了状态码兼容性
echo "<h1>页面不存在(404 Not Found)</h1>";
// 进阶:设置 302 重定向
http_response_code(302);
header('Location: https://www.example.com'); // 重定向到指定 URL
exit; // 重定向后必须终止脚本执行
// REST API 常用状态码
http_response_code(200); // 成功
http_response_code(400); // 参数错误
http_response_code(401); // 未授权
http_response_code(500); // 服务器内部错误
(2)设置响应头(Content-Type 核心)
php
<?php
// 1. 返回 HTML 响应(默认)
header('Content-Type: text/html; charset=utf-8');
echo "<h1>这是 HTML 内容</h1>";
// 2. 返回 JSON 响应(API 开发核心)
header('Content-Type: application/json; charset=utf-8');
$data = [
'code' => 200,
'msg' => '操作成功',
'data' => ['name' => 'PHP 8', 'version' => '8.3']
];
echo json_encode($data, JSON_UNESCAPED_UNICODE); // 保留中文不转义
exit;
// 3. 下载文件响应
$filename = 'demo.txt';
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename={$filename}");
header('Content-Length: ' . filesize($filename));
readfile($filename); // 输出文件内容
exit;
三、表单处理与验证(Web 开发高频场景)
表单是客户端向服务端提交数据的核心方式,PHP 8 下需兼顾数据验证 和安全防护。
3.1 表单基础结构(HTML + PHP)
php
<!-- form.html / form.php -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PHP 表单示例</title>
</head>
<body>
<!-- POST 提交到自身页面处理 -->
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<div>
<label>姓名:</label>
<input type="text" name="username" required>
</div>
<div>
<label>年龄:</label>
<input type="number" name="age" min="1" max="120">
</div>
<div>
<label>邮箱:</label>
<input type="email" name="email">
</div>
<div>
<button type="submit" name="submit">提交</button>
</div>
</form>
<?php
// PHP 8 表单处理逻辑
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])) {
// 1. 数据过滤(核心:防 XSS、格式验证)
$username = htmlspecialchars(trim($_POST['username']), ENT_QUOTES);
$age = (int)$_POST['age'] ?? 0;
$email = filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL);
// 2. 业务验证(PHP 8 条件判断优化)
$errors = [];
if (empty($username)) $errors[] = '姓名不能为空';
if ($age < 1 || $age > 120) $errors[] = '年龄需在1-120之间';
if (!$email) $errors[] = '邮箱格式错误';
// 3. 验证结果处理
if (empty($errors)) {
echo "<p style='color: green;'>提交成功!姓名:{$username},年龄:{$age}</p>";
// 后续:存入数据库/其他业务逻辑
} else {
echo "<p style='color: red;'>提交失败:" . implode('、', $errors) . "</p>";
}
}
?>
</body>
</html>
3.2 PHP 8 表单验证增强(过滤器 + 类型提示)
PHP 内置 filter 扩展(PHP 8 优化性能),是表单验证的首选工具:
php
<?php
/**
* PHP 8 表单验证函数(类型提示+过滤器)
* @param array $data 表单提交的原始数据
* @return array [bool $isValid, array $errors, array $cleanData]
*/
function validateForm(array $data): array {
$cleanData = [];
$errors = [];
// 1. 验证姓名(非空+长度限制)
$cleanData['username'] = trim($data['username'] ?? '');
if (empty($cleanData['username'])) {
$errors[] = '姓名不能为空';
} elseif (mb_strlen($cleanData['username']) > 20) {
$errors[] = '姓名长度不能超过20个字符';
}
// 2. 验证年龄(整数+范围)
$cleanData['age'] = filter_var($data['age'] ?? 0, FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1, 'max_range' => 120]
]);
if ($cleanData['age'] === false) {
$errors[] = '年龄需为1-120的整数';
$cleanData['age'] = 0; // 重置无效值
}
// 3. 验证手机号(PHP 8 正则匹配)
$cleanData['phone'] = $data['phone'] ?? '';
if (!preg_match('/^1[3-9]\d{9}$/', $cleanData['phone'])) {
$errors[] = '手机号格式错误';
}
return [empty($errors), $errors, $cleanData];
}
// 调用示例
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
[$isValid, $errors, $data] = validateForm($_POST);
if ($isValid) {
echo "验证通过:{$data['username']} - {$data['phone']}";
} else {
echo "验证失败:" . implode('<br>', $errors);
}
}
四、Session 与 Cookie 管理(状态保持核心)
HTTP 是无状态协议,Session 和 Cookie 是实现「用户状态保持」的核心方案,PHP 8 对两者的安全性做了优化。
4.1 Cookie 操作(客户端存储)
Cookie 是存储在客户端浏览器的小型文本数据,PHP 通过 setcookie()/$_COOKIE 操作:
php
<?php
// 1. 设置 Cookie(PHP 8 安全参数优化)
$cookieName = 'user_token';
$cookieValue = md5(uniqid(mt_rand(), true)); // 生成随机令牌
$expire = time() + 3600 * 24 * 7; // 有效期7天
$path = '/'; // 全站可用
$domain = ''; // 域名(如 .example.com)
$secure = false; // HTTPS 环境设为 true
$httponly = true; // 禁止 JS 访问(防 XSS 窃取)
$samesite = 'Lax'; // 防 CSRF(Strict/Lax/None)
// PHP 8 支持通过 header 手动设置(更灵活)
header("Set-Cookie: {$cookieName}={$cookieValue}; Expires=" . gmdate('D, d M Y H:i:s T', $expire) . "; Path={$path}; HttpOnly; SameSite={$samesite}");
// 2. 获取 Cookie
$token = $_COOKIE[$cookieName] ?? '';
echo "Cookie 令牌:{$token}<br>";
// 3. 删除 Cookie(设置过期时间为过去)
setcookie($cookieName, '', time() - 3600, $path, $domain, $secure, $httponly);
unset($_COOKIE[$cookieName]);
4.2 Session 操作(服务端存储)
Session 数据存储在服务端,仅通过 Cookie 传递 PHPSESSID 标识,安全性更高:
php
<?php
// 1. Session 配置(PHP 8 推荐在 php.ini 或代码中配置)
ini_set('session.name', 'PHP8_SESSID'); // 自定义 Session ID 名称
ini_set('session.cookie_httponly', '1'); // 禁止 JS 访问
ini_set('session.cookie_samesite', 'Lax'); // 防 CSRF
ini_set('session.gc_maxlifetime', 3600); // Session 有效期1小时
ini_set('session.save_path', '/tmp/php_sessions'); // 自定义存储路径
// 2. 启动 Session(必须在输出任何内容前调用)
session_start();
// 3. 设置 Session 数据
$_SESSION['user_id'] = 1001;
$_SESSION['username'] = 'PHP8用户';
$_SESSION['login_time'] = date('Y-m-d H:i:s');
// 4. 获取 Session 数据(PHP 8 空合并运算符)
$username = $_SESSION['username'] ?? '游客';
echo "当前登录用户:{$username}<br>";
// 5. 修改 Session 数据
$_SESSION['username'] = 'PHP8进阶用户';
// 6. 销毁 Session(退出登录)
// unset($_SESSION['user_id']); // 销毁单个数据
// $_SESSION = []; // 清空所有 Session 数据
// session_destroy(); // 销毁服务端 Session 文件
// setcookie(session_name(), '', time() - 3600, '/'); // 删除客户端 Session ID
实战:用户登录状态保持
php
<?php
// login.php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
// 模拟验证(实际需查数据库+密码哈希验证)
if ($username === 'admin' && $password === '123456') {
// 登录成功,设置 Session
$_SESSION['is_login'] = true;
$_SESSION['username'] = $username;
$_SESSION['login_time'] = time();
header('Location: index.php'); // 跳转到首页
exit;
} else {
echo "用户名或密码错误";
}
}
?>
<!-- index.php -->
<?php
session_start();
// 验证登录状态
if (!($_SESSION['is_login'] ?? false)) {
header('Location: login.php'); // 未登录跳转到登录页
exit;
}
echo "欢迎回来,{$_SESSION['username']}!<br>";
echo "<a href='logout.php'>退出登录</a>";
// logout.php
session_start();
$_SESSION = [];
session_destroy();
setcookie(session_name(), '', time() - 3600, '/');
header('Location: login.php');
exit;
五、PHP 8 Web 开发安全核心
Web 开发的安全问题是重中之重,PHP 8 提供了更完善的防护机制,核心需关注以下点:
5.1 XSS 防护(跨站脚本攻击)
- 核心手段:输出数据时用
htmlspecialchars()转义特殊字符; - PHP 8 优化:
ENT_QUOTES模式更稳定,支持 UTF-8 编码;
php
<?php
// 危险:直接输出用户输入
// echo $_GET['content'];
// 安全:转义后输出
$content = $_GET['content'] ?? '';
echo htmlspecialchars($content, ENT_QUOTES, 'UTF-8');
5.2 CSRF 防护(跨站请求伪造)
- 核心手段:生成 CSRF Token 并验证;
php
<?php
session_start();
// 生成 CSRF Token
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // PHP 7+ 安全随机数
}
// 表单中嵌入 Token
echo "<form method='post'>
<input type='hidden' name='csrf_token' value='{$_SESSION['csrf_token']}'>
<button type='submit'>提交</button>
</form>";
// 验证 Token
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$token = $_POST['csrf_token'] ?? '';
if (!hash_equals($_SESSION['csrf_token'], $token)) { // PHP 8 安全比较
die("CSRF 验证失败!");
}
// 正常业务逻辑
}
5.3 密码安全(PHP 8 哈希优化)
- 禁止明文存储密码,使用
password_hash()/password_verify()(PHP 8 优化算法性能);
php
<?php
// 注册:生成密码哈希
$password = '123456';
$hash = password_hash($password, PASSWORD_DEFAULT); // 默认使用 bcrypt 算法
echo "密码哈希:{$hash}<br>";
// 登录:验证密码
$inputPwd = '123456';
if (password_verify($inputPwd, $hash)) {
echo "密码验证通过<br>";
} else {
echo "密码错误<br>";
}
六、实战示例:简易用户注册登录系统
php
<?php
/**
* 核心功能:用户注册 + 登录 + 退出
* 技术点:PHP 8 类型提示、密码哈希、Session、表单验证、PDO 数据库操作
*/
// 1. 初始化配置
declare(strict_types=1);
ini_set('display_errors', '0');
ini_set('session.cookie_httponly', '1');
session_start();
// 2. 数据库连接(复用之前的 PDO 连接函数)
function connectPdo(): PDO {
$dsn = 'mysql:host=localhost;dbname=php8_demo;charset=utf8mb4';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
];
return new PDO($dsn, 'root', '123456', $options);
}
// 3. 注册函数
function register(string $username, string $password): array {
$errors = [];
// 验证参数
if (mb_strlen($username) < 3 || mb_strlen($username) > 20) {
$errors[] = '用户名长度需3-20个字符';
}
if (strlen($password) < 6) {
$errors[] = '密码长度不能少于6位';
}
if (!empty($errors)) {
return [false, $errors];
}
// 数据库操作
try {
$pdo = connectPdo();
// 检查用户名是否已存在
$stmt = $pdo->prepare("SELECT id FROM users WHERE username = :username");
$stmt->execute([':username' => $username]);
if ($stmt->fetch()) {
$errors[] = '用户名已存在';
return [false, $errors];
}
// 插入用户(密码哈希)
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (username, password) VALUES (:username, :password)");
$stmt->execute([':username' => $username, ':password' => $hash]);
return [true, ['注册成功,请登录']];
} catch (PDOException $e) {
$errors[] = '数据库错误:' . $e->getMessage();
return [false, $errors];
}
}
// 4. 登录函数
function login(string $username, string $password): array {
$errors = [];
try {
$pdo = connectPdo();
$stmt = $pdo->prepare("SELECT id, password FROM users WHERE username = :username");
$stmt->execute([':username' => $username]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user || !password_verify($password, $user['password'])) {
$errors[] = '用户名或密码错误';
return [false, $errors];
}
// 设置登录状态
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $username;
$_SESSION['is_login'] = true;
return [true, ['登录成功']];
} catch (PDOException $e) {
$errors[] = '数据库错误:' . $e->getMessage();
return [false, $errors];
}
}
// 5. 处理请求
$action = $_GET['action'] ?? 'login';
$message = '';
$msgType = 'error';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username'] ?? '');
$password = trim($_POST['password'] ?? '');
if ($action === 'register') {
[$success, $errors] = register($username, $password);
$msgType = $success ? 'success' : 'error';
$message = implode('<br>', $errors);
} elseif ($action === 'login') {
[$success, $errors] = login($username, $password);
$msgType = $success ? 'success' : 'error';
$message = implode('<br>', $errors);
if ($success) {
header('Location: ?action=index');
exit;
}
}
}
// 6. 退出登录
if ($action === 'logout') {
$_SESSION = [];
session_destroy();
setcookie(session_name(), '', time() - 3600, '/');
header('Location: ?action=login');
exit;
}
// 7. 验证登录状态(首页)
if ($action === 'index') {
if (!($_SESSION['is_login'] ?? false)) {
header('Location: ?action=login');
exit;
}
$message = "欢迎你,{$_SESSION['username']}!<br><a href='?action=logout'>退出登录</a>";
$msgType = 'success';
}
?>
<!-- HTML 页面 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PHP 8 用户系统</title>
<style>
.success { color: green; }
.error { color: red; }
.container { width: 400px; margin: 50px auto; }
form { margin-top: 20px; }
input { margin: 5px 0; padding: 8px; width: 100%; }
button { padding: 10px; width: 100%; background: #007bff; color: white; border: none; }
a { margin: 0 5px; }
</style>
</head>
<body>
<div class="container">
<h1><?php echo $action === 'login' ? '登录' : ($action === 'register' ? '注册' : '首页'); ?></h1>
<?php if ($message): ?>
<p class="<?php echo $msgType; ?>"><?php echo $message; ?></p>
<?php endif; ?>
<?php if ($action === 'login' || $action === 'register'): ?>
<form method="post">
<div>
<label>用户名:</label>
<input type="text" name="username" required>
</div>
<div>
<label>密码:</label>
<input type="password" name="password" required>
</div>
<button type="submit"><?php echo $action === 'login' ? '登录' : '注册'; ?></button>
</form>
<div>
<?php echo $action === 'login' ? '还没有账号?<a href="?action=register">去注册</a>' : '已有账号?<a href="?action=login">去登录</a>'; ?>
</div>
<?php endif; ?>
</div>
</body>
</html>