PHP面向对象04:PDO

一、PDO概述

  • PDO 提供了一套帮助用户实现多数据库操作的统一接口,通过使用PDO,开发人员不需要额外自定义数据库对应的操作类,从而简化开发过程。
  • PDO 类:实现统一的数据库的初始化操作,包括连接认证和执行SQL指令。
  • PDOStatement 类:数据解析操作,主要针对数据结果操作(有数据结果返回)。
  • PDOException 类:异常处理操作,针对所有PDO操作可能出现的错误采用的异常处理模式。

二、PDO操作

1. PDO类基本应用

  • PDO::__construct():实例化PDO对象。

    • __construct(string $dsn, string $user, string $pass[, array $drivers]) 实现实例化对象。
    • 构造方法由4个参数组成,前三个必填,第四个可选。
    • $dsn:一个数据库基本信息字符串,包含数据库产品、主机地址等。
      1. 驱动名字(数据库产品),使用:分隔。
      2. 驱动选项(主机地址):使用host=具体主机地址,跟在驱动名字之后
      3. 驱动选项(端口):使用port=端口号,默认为3306可以不写,拼凑在驱动名字后,不区分先后顺序。
      4. 驱动选项(数据库名字):使用dbname=数据库名字(可以事先没有)
    • $drivers:PDO属性设置,是关联数组,利用PDO内部的常量进行设置。
  • PDO::exec():执行写操作SQL指令,返回受影响的行数

  • PDO::query():执行一个读操作SQL指令,返回一个 PDOStatement 类对象。

  • PDO::errorCode()PDO::errorInfo():获取上次错误的信息。

  • SQL 执行的结果不论是写操作还是读操作都有可能出错,因此需要进行错误处理。

<?php

$dsn = 'mysql:host=localhost;dbname=test';
$user = 'root';
$pass = "";
$pdo = new PDO($dsn, $user, $pass);

# 写数据
$sql = "update test set id = 2 where id = 1";
$res = $pdo->exec($sql);
var_dump($res);

# 读数据
$sql = "select * from test";
$res = $pdo->query($sql);

# 判定结果,错误处理
if ($res === false) {
    echo "SQL错误" . "<br>";
    echo "错误代码为:" . $pdo->errorCode() . "<br>";
    echo "错误原因为:" . $pdo->errorInfo()[2] . "<br>";
    exit;
}
var_dump($res);

2. 写操作

  • 实际使用 PDO 的时候,都会进行二次封装,因为PDO的操作有很多本身不够完善。
  • PDO可以独立完成写操作功能,而不需要其他两个工具类。
  • PDO的写操作其实本质要注意的是执行SQL时可能出现的错误处理(注意外部数据)。
  • 写操作中唯一不同的是插入操作,因为可能需要获取自增长ID,此时需要多一个步骤(功能)。
<?php
# 初始化封装函数
function pdo_init() {
    $dsn = 'mysql:host=localhost;dbname=test';
    $pdo = @new PDO($dsn, 'root', "");
    if (!$pdo) {
        die("数据库连接认证失败");
    }
    # 字符集
    $pdo->exec('set names utf8');
    return $pdo;
}

# 写操作封装函数
function pdo_exec(PDO $pdo, $sql) {
    $res = $pdo->exec($sql);
    # 错误判定
    if ($res === false) {
        echo "SQL错误" . "<br>";
        echo "错误代码为:" . $pdo->errorCode() . "<br>";
        echo "错误原因为:" . $pdo->errorInfo()[2] . "<br>";
        exit;
    }
    return $res;
}


$pdo = pdo_init();
$res = pdo_exec($pdo, "insert test values(4, 'wwww')");
var_dump($res);

3. 查询操作

  • 通过PDO::query()执行查询SQL得到PDOStatement对象,然后PDOStatement对象下有一系列fetch方法可以实现数据查询,得到PHP可以识别的数组数据。
  • PDO实现查询通常也需要进行二次封装,保证SQL执行安全,也方便用户获取目标数据。
<?php
# 初始化封装函数
function pdo_init() {
    $dsn = 'mysql:host=localhost;dbname=test';
    $pdo = @new PDO($dsn, 'root', "");
    if (!$pdo) {
        die("数据库连接认证失败");
    }
    # 字符集
    $pdo->exec('set names utf8');
    return $pdo;
}

# 查询操作封装
function pdo_query(PDO $pdo, string $sql) {
    $stmt = $pdo->query($sql);
    # 错误判定
    if ($stmt === false) {
        echo "SQL错误" . "<br>";
        echo "错误代码为:" . $pdo->errorCode() . "<br>";
        echo "错误原因为:" . $pdo->errorInfo()[2] . "<br>";
        exit;
    }
    return $stmt;
}

# 读取数据,默认只获取一条记录
function pdo_get(PDOStatement $stmt, $only = true, $fetchStyle = PDO::FETCH_ASSOC) {
    if ($only) {
        return $stmt->fetch($fetchStyle);
    } else {
        return $stmt->fetchAll($fetchStyle);
    }

}

$pdo = pdo_init();
$stmt = pdo_query($pdo, "select * from test");
var_dump(pdo_get($stmt));
var_dump(pdo_get($stmt, false));

4. PDO事务功能

  • 事务执行是否成功由MySQL对应的存储引擎是否支持决定。
  • 事务功能:事务是指将默认的机制(一次操作,系统就会有一次写入数据表)改变为通过事务日志记录操作,最后通过一次性操作写入到数据表。
    • 开启事务:start transaction,写操作停止直接写入数据表,而是记录到事务日志。
    • 事务操作:具体的写操作,通常多个步骤多条指令。
    • 提交事务:即事务操作结束。成功提交:commit,所有事物日志内容同步到数据表,并清空当前事务日志。失败回滚:rollback,直接清空当前事务日志。
  • PDO类提供的事务操作:
    • PDO::beginTransaction():开启事务
    • PDO::exec():执行事务(写操作)
    • PDO::rollback():回滚所有事务
    • PDO::commit():成功提交所有事务
<?php
# 实例化PDO对象
$pdo = @new PDO('mysql:host=localhost;dbname=test', 'root', "");

# 开启事务
$pdo->beginTransaction() or die("事务开启失败");

# 执行事务
$pdo->exec("insert into test values (5,'4444')");

# 设置回滚点
$pdo->exec('savepoint sp1');

# 终止事务
$pdo->commit();
$pdo->rollBack();

三、PDO异常

1. PHP异常机制

  • 如果想要实现异常处理,必须借助于系统提供的 set_error_handler 来告知系统我们想采用的处理模式。
  • 异常机制是利用 try{}catch(Exception $e){} 来进行捕捉和处理的。
<?php
set_error_handler(function () {
    throw new Exception('错误回调修改默认异常处理模式');
});
try {
    $res = $n1 / $n2;
} catch (Exception $exception) {
    echo "代码运行出错<br>";
    echo "错误文件为:" . $exception->getFile() . '<br>';
    echo "错误行号为:" . $exception->getLine() . '<br>';
    echo "错误描述为:" . $exception->getMessage() . '<br>';

    die();
}

2. PDO错误机制

  • PDO错误机制是指PDO在使用过程中出现了错误(SQL指令执行错误)的时候,PDO处理错误的方式。
  • PDO提供了三种错误机制,是通过PDO的常量PDO::ATTR_ERRMODE来选择的
    • PDO::ERRMODE_SILENT:静默模式,出错了不处理(默认的)
    • PDO::ERRMODE_WARNING:警告模式,出错了马上给出错误提示
    • PDO::ERRMODE_EXCEPTION:异常模式,出错了将错误交给异常PDOException对象。
<?php
$pdo = @new PDO('mysql:host=localhost;dbname=test', 'root', "");
$pdo->exec('set names utf8');

# 警告模式
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$pdo->exec('insert into test values');

# 异常模式
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
    $pdo->exec('insert into test values');
} catch (Exception $e) {
    echo "SQL运行错误" . "<br>";
    echo "错误代码为:" . $pdo->errorCode() . "<br>";
    echo "错误原因为:" . $pdo->errorInfo()[2] . "<br>";
    exit;
}

3. PDOException异常处理

  • 在初始化PDO对象的时候,利用第四个参数来设定。
  • 初始化PDO后,利用PDO::setAttribute()方法来修改错误模式。
# 初始化PDO时设定错误模式
$drivers = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
try {
    $pdo = @new PDO('mysql:host=localhost;dbname=test', 'root', "", $drivers);
} catch (Exception $e) {
    echo "数据库连接失败!<br>";
    echo "错误文件为:" . $e->getFile() . "<br>";
    echo "错误行号为:" . $e->getLine() . "<br>";
    echo "错误描述为:" . $e->getMessage();
    die();
}

四、预处理

1. MySQL预处理

  • prepare 预处理:是指客户端将要执行的SQL先发送给服务器,服务器先进行编译,不执行,等到客户端需要服务器端执行的时候,发送一条执行指令,让服务器再执行已经提前处理好(预处理)的SQL指令。
  • 实现预处理
    1. 发送预处理:prepare 预处理名字 from ‘要重复执行的SQL指令’;
    2. 执行预处理:execute 预处理名字
    prepare student_select from 'select * from students';
    execute student_select;
    
  • 预处理占位
    • 预处理占位符:在预处理指令中要执行的SQL指令,使用?来代替未知数据部分。
    • 预处理执行(using):在执行预处理的时候将对应的数据携带到预处理指令中。
    prepare student_select from 'select * from students where id=? and name=?';
    set @id = 1;
    set @name = "张三";
    execute student_select  using @id,@name;
    
  • 删除预处理
    drop prepare student_select;
    

2. PDO预处理

  • PDO 提供了一套方法机制
    • PDO::prepare():发送预处理指令,只需要提供要执行的指令即可,不需要prepare名字from。成功返回PDOStatement类对象,失败返回false(或异常错误)
    • PDOStatement::bindParam():绑定预处理所需要的参数,只能绑定变量(引用传递)
    • PDOStatement::bindValue():绑定预处理所需要的参数,只能绑定值(值传递)
    • PDOStatement::execute():执行预处理,成功返回true,失败返回false
  • bindValue 和 bindParam 的区别
    • bindValue 绑定数据的方式灵活,可以是变量也可以是数据常量。
    • bindParam 只能是变量。
<?php
$drivers = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
$pdo = @new PDO('mysql:host=localhost;dbname=test', 'root', "", $drivers);

# 发送预处理指令
$pre_sql = "select * from test where id = :id";
$stmt = $pdo->prepare($pre_sql);

# 绑定参数
$stmt->bindValue(":id", 4);

# 执行预处理
$res = $stmt->execute();
if (!$res) die("执行失败");

# 获取结果
$line = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($line);

五、封装PDO

  • PDO的使用时经常性的,需要将PDO变得更加灵活,实现代码复用,所以需要对PDO进行二次封装。
<?php

namespace core;

use \PDO, \PDOStatement, \PDOException;

class Dao {
    private $pdo;
    private $fetchMode;

    public function __construct($databaseInfo = array(), $drivers = array()) {
        $type = $databaseInfo['type'] ?? 'mysql';
        $host = $databaseInfo['host'] ?? 'localhost';
        $port = $databaseInfo['port'] ?? '3306';
        $user = $databaseInfo['user'] ?? 'root';
        $pass = $databaseInfo['pass'] ?? '';
        $dbname = $databaseInfo['dbname'] ?? 'test';
        $charset = $databaseInfo['charset'] ?? 'utf8';

        # 驱动控制
        $this->fetchMode = $databaseInfo['fetch_mode'] ?? PDO::FETCH_ASSOC;
        $drivers[PDO::ATTR_ERRMODE] = $drivers[PDO::ATTR_ERRMODE] ?? PDO::ERRMODE_EXCEPTION;

        # 实例化PDO对象
        try {
            $this->pdo = @new PDO($type . ":host=" . $host . ";port=" . $port . ";dbname=" . $dbname, $user, $pass, $drivers);
        } catch (PDOException $e) {
            $this->dao_exception($e, "数据库连接失败!");
        }
        # 设定字符集
        try {
            $this->pdo->exec("set names {$charset}");
        } catch (PDOException $e) {
            $this->dao_exception($e);
        }
    }

    # 写操作
    public function dao_exec($sql) {
        try {
            return $this->pdo->exec($sql);
        } catch (PDOException $e) {
            $this->dao_exception($e);
        }
    }

    # 获取自增长ID
    public function dao_insert_id() {
        return $this->pdo->lastInsertId();
    }

    # 读操作
    public function dao_query($sql, $only = true) {
        try {
            $stmt = $this->pdo->query($sql);
            $stmt->setFetchMode($this->fetchMode);
            if ($only) {
                $row = $stmt->fetch();
                if (!$row) throw new PDOException("当前查询没有数据");
                return $row;
            } else {
                $rows = $stmt->fetchAll();
                if (!$rows) throw new PDOException("当前查询没有数据");
                return $rows;
            }
        } catch (PDOException $e) {
            $this->dao_exception($e);
        }
    }

    private function dao_exception($e, $tip = "SQL执行错误!") {
        echo $tip . "<br>";
        echo "错误文件为:" . $e->getFile() . "<br>";
        echo "错误行号为:" . $e->getLine() . "<br>";
        echo "错误描述为:" . $e->getMessage();
        die();
    }
}

$dao = new Dao();
$line = $dao->dao_query("select * from test", false);

var_dump($line);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iFulling

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值