PDO介绍与连接

什么是PDO

PDO(PHP Data Objects)是PHP5.0.1版本引入的一个数据库抽象层,它提供了一个统一的数据访问接口。通过PDO,我们可以使用相同的方式访问多种不同的数据库系统,而不需要学习特定的数据库API。

PDO的核心特性

  • 数据库无关性:一套API支持多种数据库
  • 面向对象接口:完全的面向对象设计
  • 错误处理:支持异常处理机制
  • 预处理语句:内置SQL注入防护
  • 事务支持:完整的ACID事务支持
  • 存储过程:支持调用数据库存储过程

启用PDO扩展

在使用PDO之前,需要确保相应的PDO驱动已经启用。

检查PDO支持

<?php
// 检查PDO是否可用
if (extension_loaded('pdo')) {
    echo "PDO支持已启用\n";
} else {
    echo "PDO支持未启用\n";
}

// 查看已安装的PDO驱动
print_r(PDO::getAvailableDrivers());
?>

启用扩展

php.ini文件中启用相应的PDO扩展:

; 启用PDO核心
extension=pdo

; 启用特定数据库驱动
extension=pdo_mysql      ; MySQL驱动
extension=pdo_pgsql      ; PostgreSQL驱动
extension=pdo_sqlite     ; SQLite驱动
extension=pdo_sqlsrv     ; SQL Server驱动

PDO连接语法

基本连接语法

<?php
try {
    // 创建PDO连接
    $pdo = new PDO($dsn, $username, $password, $options);
    echo "数据库连接成功!";
} catch (PDOException $e) {
    echo "连接失败: " . $e->getMessage();
}
?>

连接参数说明

  • $dsn:数据源名称,指定数据库类型和连接信息
  • $username:数据库用户名
  • $password:数据库密码
  • $options:连接选项数组(可选)

不同数据库的连接方式

MySQL连接

<?php
$host = 'localhost';
$dbname = 'test_db';
$username = 'root';
$password = 'password';
$charset = 'utf8mb4';

// MySQL DSN格式
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";

$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

try {
    $pdo = new PDO($dsn, $username, $password, $options);
    echo "MySQL连接成功!";
} catch (PDOException $e) {
    echo "MySQL连接失败: " . $e->getMessage();
}
?>

SQLite连接

<?php
// 文件数据库
$db_path = __DIR__ . '/database.db';

// SQLite DSN格式
$dsn = "sqlite:$db_path";

try {
    $pdo = new PDO($dsn);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo "SQLite连接成功!";
} catch (PDOException $e) {
    echo "SQLite连接失败: " . $e->getMessage();
}
?>

连接选项详解

常用连接选项

<?php
$options = [
    // 错误处理模式
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,

    // 默认获取模式
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,

    // 禁用预处理模拟
    PDO::ATTR_EMULATE_PREPARES   => false,

    // 设置字符集
    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4",

    // 连接超时时间(秒)
    PDO::ATTR_TIMEOUT           => 30,

    // 持久化连接
    PDO::ATTR_PERSISTENT        => true,

    // 自动提交模式
    PDO::ATTR_AUTOCOMMIT        => true,
];

$pdo = new PDO($dsn, $username, $password, $options);
?>

错误处理模式详解

<?php
// 1. 静默模式(默认)
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
// 错误时只返回false,不产生任何输出

// 2. 警告模式
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
// 错误时产生E_WARNING级别的警告

// 3. 异常模式(推荐)
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 错误时抛出PDOException异常
?>

连接管理最佳实践

1. 使用try-catch处理连接错误

<?php
function createPdoConnection($dsn, $username, $password) {
    try {
        $options = [
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES   => false,
            PDO::ATTR_PERSISTENT        => false,
        ];

        return new PDO($dsn, $username, $password, $options);

    } catch (PDOException $e) {
        // 记录错误日志
        error_log("数据库连接失败: " . $e->getMessage());

        // 返回null或抛出自定义异常
        return null;
    }
}

// 使用示例
$pdo = createPdoConnection($dsn, $username, $password);
if ($pdo === null) {
    die("无法连接到数据库");
}
?>

2. 配置文件管理

<?php
// config/database.php
class DatabaseConfig {
    const HOST = 'localhost';
    const DBNAME = 'myapp';
    const USERNAME = 'user';
    const PASSWORD = 'password';
    const CHARSET = 'utf8mb4';
    const OPTIONS = [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES   => false,
    ];

    public static function getDsn() {
        return sprintf(
            "mysql:host=%s;dbname=%s;charset=%s",
            self::HOST,
            self::DBNAME,
            self::CHARSET
        );
    }
}

// 使用示例
$pdo = new PDO(
    DatabaseConfig::getDsn(),
    DatabaseConfig::USERNAME,
    DatabaseConfig::PASSWORD,
    DatabaseConfig::OPTIONS
);
?>

连接安全注意事项

1. 保护敏感信息

<?php
// 不要将数据库凭据硬编码在代码中
// 使用环境变量或配置文件

// 好的做法:
$host = $_ENV['DB_HOST'] ?? 'localhost';
$dbname = $_ENV['DB_NAME'] ?? 'test';
$username = $_ENV['DB_USER'] ?? 'root';
$password = $_ENV['DB_PASS'] ?? '';

// 坏的做法:
$host = 'localhost';
$username = 'root';
$password = 'password123'; // 暴露在代码中
?>

2. 连接超时设置

<?php
$options = [
    PDO::ATTR_TIMEOUT => 10, // 10秒连接超时
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
];

$pdo = new PDO($dsn, $username, $password, $options);
?>

调试连接问题

常见连接错误及解决方法

<?php
try {
    $pdo = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
    $errorCode = $e->getCode();
    $errorMessage = $e->getMessage();

    switch ($errorCode) {
        case 1045:
            echo "错误:用户名或密码错误";
            break;
        case 1049:
            echo "错误:数据库不存在";
            break;
        case 2002:
            echo "错误:无法连接到数据库服务器";
            break;
        case 2003:
            echo "错误:数据库服务器拒绝连接";
            break;
        default:
            echo "数据库连接错误: $errorMessage";
    }
}
?>

通过本节的学习,你应该掌握了PDO的基本概念、连接方法和配置技巧。下一节我们将学习如何使用PDO进行基本的数据库操作。