PHP mysqli 连接:面向对象与过程式风格解析与优化实践

心靈之曲
发布: 2025-11-05 12:21:30
原创
976人浏览过

PHP mysqli 连接:面向对象与过程式风格解析与优化实践

本文深入探讨 php `mysqli` 扩展中面向对象与过程式两种风格的用法与转换。我们将对比二者差异,纠正常见错误,并提供从面向对象到过程式风格的转换示例。文章强调在现代 php 开发中,应优先选择面向对象风格或 pdo,并展示如何通过启用错误报告和简化结果获取来编写更简洁、健壮的数据库交互代码。

在 PHP 数据库交互中,mysqli 扩展提供了两种主要的操作风格:面向对象(Object-Oriented, OO)和过程式(Procedural)。理解这两种风格的差异及其适用场景,对于编写高效且可维护的数据库代码至关重要。

mysqli 的面向对象与过程式风格

mysqli 扩展最初设计时,面向对象风格是其推荐的使用方式,而过程式风格主要是为了帮助那些从旧版 PHP(如 PHP 4 的 mysql 扩展)迁移的用户平滑过渡。因此,在新的项目或代码中,强烈建议采用面向对象风格。

两者核心差异在于函数调用方式和参数传递:

  • 面向对象风格:通过 mysqli 类的实例调用方法,例如 $mysqli->prepare()。
  • 过程式风格:通过全局函数调用,并将 mysqli 实例作为第一个参数传入,例如 mysqli_prepare($mysqli, ...)。

值得注意的是,使用 mysqli 的面向对象风格并不意味着您的整个应用程序就必须是面向对象的。它仅仅是一种更现代、更清晰的 API 使用方式。

立即学习PHP免费学习笔记(深入)”;

常见的错误尝试与原因分析

用户在尝试将面向对象风格的代码转换为过程式时,常会遇到以下错误:

$connection = mysqli_connect('localhost', 'root', '', 'ems');
$query = "SELECT * FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?";
$get_dates = mysqli_query($connection, $query); // 错误的使用方式
while($row = mysqli_fetch_assoc($get_dates)){
    $booked_dates[] = $row['event_date'];
}
登录后复制

这段代码会抛出 Fatal error: Uncaught TypeError: mysqli_fetch_assoc(): Argument #1 ($result) must be of type mysqli_result 错误。

错误原因: 问题在于 mysqli_query() 函数的使用。mysqli_query() 适用于执行不带参数的简单查询,或者在非预处理语句模式下获取结果。当使用带有占位符(?)的预处理语句时,您不能直接将其传递给 mysqli_query()。预处理语句需要经过 prepare、bind_param、execute 等一系列步骤才能正确执行和获取结果。mysqli_query() 在这种情况下会返回 false(表示查询失败,因为 SQL 语法不完整或不被支持),而不是 mysqli_result 对象,导致后续 mysqli_fetch_assoc() 接收到错误类型的参数。

面向对象 mysqli 代码转换为过程式风格

尽管不推荐,但了解如何将面向对象风格的代码转换为过程式风格,有助于理解 mysqli 的内部机制。以下是将原始面向对象代码转换为过程式风格的示例:

原始面向对象代码:

飞书多维表格
飞书多维表格

表格形态的AI工作流搭建工具,支持批量化的AI创作与分析任务,接入DeepSeek R1满血版

飞书多维表格 26
查看详情 飞书多维表格
function build_calendar($month, $year){
    $mysqli = new mysqli('localhost', 'root', '', 'ems');
    $stmt = $mysqli->prepare("SELECT * FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");
    $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();
        }
    }
    // 返回 $bookings 数组
    return $bookings;
}
登录后复制

转换为过程式风格:

function build_calendar_procedural($month, $year)
{
    // 1. 建立数据库连接
    $mysqli = mysqli_connect('localhost', 'root', '', 'ems');
    if (mysqli_connect_errno()) {
        // 错误处理:连接失败
        error_log("Failed to connect to MySQL: " . mysqli_connect_error());
        return []; // 返回空数组或抛出异常
    }

    // 2. 准备预处理语句
    $stmt = mysqli_prepare($mysqli, "SELECT * FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");
    if (!$stmt) {
        // 错误处理:语句准备失败
        error_log("Failed to prepare statement: " . mysqli_error($mysqli));
        mysqli_close($mysqli);
        return [];
    }

    // 3. 绑定参数
    mysqli_stmt_bind_param($stmt, 'ss', $month, $year);

    $bookings = array();
    // 4. 执行语句
    if (mysqli_stmt_execute($stmt)) {
        // 5. 获取结果集
        $result = mysqli_stmt_get_result($stmt);
        if ($result) { // 检查结果集是否成功获取
            // 6. 检查行数并遍历结果
            if (mysqli_num_rows($result) > 0) {
                while ($row = mysqli_fetch_assoc($result)) {
                    $bookings[] = $row['event_date'];
                }
            }
            mysqli_free_result($result); // 释放结果集内存
        } else {
            // 错误处理:获取结果集失败
            error_log("Failed to get result set: " . mysqli_stmt_error($stmt));
        }
    } else {
        // 错误处理:语句执行失败
        error_log("Failed to execute statement: " . mysqli_stmt_error($stmt));
    }

    // 7. 关闭语句和数据库连接
    mysqli_stmt_close($stmt);
    mysqli_close($mysqli);

    return $bookings;
}
登录后复制

可以看到,过程式风格的函数调用方式只是将面向对象方法名转换为以 mysqli_ 或 mysqli_stmt_ 开头的函数名,并将 mysqli 或 stmt 对象作为第一个参数传入。

推荐的现代 mysqli 实践与优化

为了编写更健壮、简洁且易于维护的数据库代码,建议遵循以下实践:

  1. 坚持使用面向对象风格 mysqli 或 PDO:

    • PDO (PHP Data Objects) 是更推荐的选择,因为它提供了一致的接口来连接多种数据库,并且通常具有更简洁的 API。
    • 如果必须使用 mysqli,请始终选择面向对象风格。
  2. 启用 mysqli 错误报告: 默认情况下,mysqli 错误可能不会直接抛出异常,而是返回 false 或 null,需要手动检查。通过启用错误报告,可以将 mysqli 错误转换为异常,从而简化错误处理。

    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    // 之后,任何 mysqli 错误都会抛出 mysqli_sql_exception 异常
    登录后复制
  3. 简化结果获取: 对于获取所有行,可以使用 fetch_all(MYSQLI_ASSOC) 一次性获取所有结果,而不是手动循环 while($row = $result->fetch_assoc())。

优化后的面向对象 mysqli 示例:

// 在应用程序初始化阶段设置错误报告,通常在连接数据库之前
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

// 数据库连接对象通常作为全局变量或通过依赖注入传递
// 确保只创建一次连接
$mysqli_connection = new mysqli('localhost', 'root', '', 'ems');

/**
 * 从数据库中获取指定月份和年份的预订日期。
 *
 * @param mysqli $mysqli 数据库连接对象。
 * @param string $month 月份(例如 '01' 到 '12')。
 * @param string $year 年份。
 * @return array 预订日期数组,例如 ['YYYY-MM-DD', ...]。
 * @throws mysqli_sql_exception 如果数据库操作失败。
 */
function build_calendar_optimized(mysqli $mysqli, string $month, string $year): array
{
    // 准备预处理语句
    $stmt = $mysqli->prepare("SELECT event_date FROM bookings WHERE MONTH(event_date) = ? AND YEAR(event_date)=?");

    // 绑定参数
    // 'ss' 表示两个参数都是字符串类型
    $stmt->bind_param('ss', $month, $year);

    // 执行语句
    $stmt->execute();

    // 获取结果集
    $result = $stmt->get_result();

    // 使用 fetch_all(MYSQLI_ASSOC) 一次性获取所有结果并返回关联数组
    // array_column 用于从结果集中提取 'event_date' 列
    $bookings_data = $result->fetch_all(MYSQLI_ASSOC);

    // 提取 'event_date' 列的值
    return array_column($bookings_data, 'event_date');
}

// 示例调用
try {
    $bookings = build_calendar_optimized($mysqli_connection, '01', '2020');
    print_r($bookings);
} catch (mysqli_sql_exception $e) {
    echo "数据库操作失败: " . $e->getMessage();
    // 记录错误或向用户显示友好信息
} finally {
    // 确保在所有操作完成后关闭连接(如果连接不是持久化的)
    // 在 Web 应用中,PHP 脚本执行结束时通常会自动关闭连接
    // $mysqli_connection->close();
}
登录后复制

在这个优化后的版本中:

  • 通过 mysqli_report() 实现了更强大的错误处理。
  • 函数接收 mysqli 对象作为参数,提高了代码的模块化和可测试性。
  • 使用 fetch_all(MYSQLI_ASSOC) 简化了结果的获取和处理,减少了循环代码。
  • 使用类型提示 (string, array, mysqli) 提高了代码的可读性和健壮性。

总结

尽管 mysqli 提供了面向对象和过程式两种风格,但在现代 PHP 开发中,强烈推荐使用面向对象风格,或更进一步选择 PDO。面向对象风格的 mysqli 提供了更清晰、更现代的 API。通过启用错误报告 (mysqli_report) 和利用 fetch_all 等高级功能,可以编写出更简洁、更健壮、更易于维护的数据库交互代码。避免使用 mysqli_query 处理预处理语句,并始终遵循预处理语句的正确流程:准备、绑定参数、执行、获取结果。

以上就是PHP mysqli 连接:面向对象与过程式风格解析与优化实践的详细内容,更多请关注php中文网其它相关文章!

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号