
本文深入探讨了 php `mysqli` 扩展中面向对象 (oop) 和过程式 (procedural) 两种编程风格的异同,通过具体代码示例演示了如何进行转换。文章强调了 oop 风格的优势,并推荐采用简化的 oop 风格或更高级的 pdo 扩展,以提升代码的可读性、维护性和安全性,避免常见的数据库操作误区。
引言
PHP mysqli 扩展为开发者提供了与 MySQL 数据库交互的能力,它支持两种主要的编程风格:面向对象 (OOP) 和过程式 (procedural)。对于习惯了过程式编程的开发者而言,初次接触面向对象风格可能会感到不适,但理解这两种风格的差异及其适用场景,对于编写高效、安全的数据库代码至关重要。本文将详细解析这两种风格,展示它们之间的转换方法,并提出在现代 PHP 开发中推荐的最佳实践。
理解 mysqli 的两种编程风格
mysqli 扩展旨在提供 mysql 扩展的增强替代品,并引入了面向对象接口。尽管如此,它也提供了一套过程式接口,主要是为了方便从旧版 mysql 扩展迁移代码。
面向对象 (OOP) 风格
在 OOP 风格中,我们首先创建一个 mysqli 类的实例来建立数据库连接,然后通过这个对象调用其方法来执行数据库操作。这种风格通常被认为是更现代、更易于理解和维护的方式。
示例:OOP 风格的数据库查询
立即学习“PHP免费学习笔记(深入)”;
function build_calendar_oop($month, $year){
// 建立数据库连接
$mysqli = new mysqli('localhost', 'root', '', 'ems');
if ($mysqli->connect_error) {
die("数据库连接失败: " . $mysqli->connect_error);
}
// 预处理语句
$stmt = $mysqli->prepare("SELECT event_date FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");
if (!$stmt) {
die("预处理语句失败: " . $mysqli->error);
}
// 绑定参数
$stmt->bind_param('ss', $month, $year);
$bookings = array();
// 执行语句
if($stmt->execute()){
// 获取结果集
$result = $stmt->get_result();
if($result->num_rows > 0){
// 遍历结果
while($row = $result->fetch_assoc()){
$bookings[] = $row['event_date'];
}
}
// 关闭语句
$stmt->close();
} else {
die("语句执行失败: " . $stmt->error);
}
// 关闭连接
$mysqli->close();
// 返回预订日期数组
return $bookings;
}
过程式 (Procedural) 风格
过程式风格则通过一系列以 mysqli_ 开头的函数来执行操作,其中许多函数都需要将 mysqli 连接对象作为第一个参数传入。这种风格对于习惯了早期 PHP 数据库函数(如 mysql_connect, mysql_query)的开发者来说可能更熟悉。
示例:过程式风格的数据库查询
function build_calendar_procedural($month, $year)
{
// 建立数据库连接
$mysqli = mysqli_connect('localhost', 'root', '', 'ems');
// 检查连接是否成功
if (mysqli_connect_errno()) {
die("数据库连接失败: " . mysqli_connect_error());
}
// 预处理语句
$stmt = mysqli_prepare($mysqli, "SELECT event_date FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");
// 检查语句是否准备成功
if (!$stmt) {
die("预处理语句失败: " . mysqli_error($mysqli));
}
// 绑定参数
mysqli_stmt_bind_param($stmt, 'ss', $month, $year);
$bookings = array();
// 执行语句
if (mysqli_stmt_execute($stmt)) {
// 获取结果集
$result = mysqli_stmt_get_result($stmt);
if ($result && mysqli_num_rows($result) > 0) {
// 遍历结果
while ($row = mysqli_fetch_assoc($result)) {
$bookings[] = $row['event_date'];
}
}
// 关闭语句
mysqli_stmt_close($stmt);
} else {
die("语句执行失败: " . mysqli_stmt_error($stmt));
}
// 关闭连接
mysqli_close($mysqli);
return $bookings;
}
核心区别:
两种风格的主要区别在于函数调用方式。OOP 风格通过对象方法调用,例如 $mysqli->prepare();而过程式风格则通过全局函数调用,并将连接对象作为第一个参数传入,例如 mysqli_prepare($mysqli, …)。从功能上讲,它们是等效的。
两种风格的等效转换
理解了两种风格后,我们可以看到它们之间存在直接的函数映射关系。以下是一些常见的转换示例:
| OOP 风格方法 | 过程式风格函数 | 描述 |
|---|---|---|
| $mysqli = new mysqli(…) | mysqli_connect(…) | 建立数据库连接 |
| $mysqli->prepare(…) | mysqli_prepare($mysqli, …) | 预处理 SQL 语句 |
| $stmt->bind_param(…) | mysqli_stmt_bind_param($stmt, …) | 绑定参数 |
| $stmt->execute() | mysqli_stmt_execute($stmt) | 执行预处理语句 |
| $stmt->get_result() | mysqli_stmt_get_result($stmt) | 获取结果集 |
| $result->num_rows | mysqli_num_rows($result) | 获取结果集行数 |
| $result->fetch_assoc() | mysqli_fetch_assoc($result) | 关联数组形式获取一行 |
| $stmt->close() | mysqli_stmt_close($stmt) | 关闭预处理语句 |
| $mysqli->close() | mysqli_close($mysqli) | 关闭数据库连接 |
通过这些映射,我们可以将 OOP 风格的代码片段完全转换为过程式风格,反之亦然。
最佳实践与现代化建议
尽管 mysqli 提供了两种风格,但在现代 PHP 开发中,有一些重要的考量和更推荐的做法。
为什么推荐面向对象风格
过程式 mysqli 风格的设计初衷主要是为了帮助那些从 PHP 4 的 mysql_* 扩展迁移代码的开发者。在新的代码库中,通常不建议使用过程式风格。OOP 风格提供了更清晰、更一致的接口,尽管使用它并不意味着你必须编写完整的面向对象应用程序,但它确实是 mysqli 扩展推荐和更直观的用法。
简化 mysqli 面向对象代码
原有的 OOP 风格代码在处理结果集时,需要手动遍历 while($row = $result->fetch_assoc()),这在某些情况下可以进一步简化。通过配置 mysqli 的错误报告模式并利用 fetch_all 方法,我们可以使代码更加简洁和健鲁。
推荐的简化 OOP 风格示例:
// 在应用初始化阶段配置错误报告,例如在连接数据库之前
// 这会将mysqli的错误转换为PHP异常,有助于更早发现问题
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
// 建立数据库连接,通常作为参数传递或在全局范围内管理
$mysqli_conn = new mysqli('localhost', 'root', '', 'ems');
// 推荐设置字符集,避免乱码问题
$mysqli_conn->set_charset("utf8mb4");
/**
* 构建日历预订日期数组
*
* @param mysqli $mysqli 数据库连接对象
* @param int $month 月份
* @param int $year 年份
* @return array 预订日期数组
*/
function build_calendar_simplified_oop(mysqli $mysqli, $month, $year): array
{
// 预处理语句
$stmt = $mysqli->prepare("SELECT event_date FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");
// 绑定参数
$stmt->bind_param('ss', $month, $year);
// 执行语句
$stmt->execute();
// 获取所有结果并以关联数组形式返回
$result = $stmt->get_result();
$bookings_raw = $result->fetch_all(MYSQLI_ASSOC);
// 如果只需要event_date的值,可以进一步处理
return array_column($bookings_raw, 'event_date');
}
// 示例调用
$bookings_for_jan_2020 = build_calendar_simplified_oop($mysqli_conn, 1, 2020);
print_r($bookings_for_jan_2020);
// 在应用结束时关闭连接
以上就是PHP mysqli 数据库操作:面向对象与过程式风格的转换与最佳实践的详细内容,更多请关注php中文网其它相关文章!


