目錄
PDO 實例" >PDO 實例
dns 參數
PDO 物件屬性" >PDO 物件屬性
查詢語句" >查詢語句
普通查詢及遍歷
查詢結果集(陣列、物件)
查詢結果集(類別)
查询结果集(指定字段)
增、删、改操作" >增、删、改操作
增加操作
修改操作
删除操作
总结" >总结
首頁 後端開發 PHP問題 三分鐘帶你了解PHP中的初始化PDO及原始SQL語句操作

三分鐘帶你了解PHP中的初始化PDO及原始SQL語句操作

Jun 21, 2021 pm 03:26 PM
php

這篇文章跟大家介紹一下PHP中的初始化PDO及原始SQL語句操作。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

三分鐘帶你了解PHP中的初始化PDO及原始SQL語句操作

PDO 已經是 PHP 中操作資料庫事實上的標準。包括現在的框架和各種類別庫,都是以 PDO 作為資料庫的連結方式。基本上只有我們自己在寫簡單的測試程式碼或小的功能時會使用 mysqli 來操作資料庫。注意,普通的 mysql 擴充已經過時了哦!

PDO 實例

首先來看看一個 PDO 實例是如何初始化的。

$dns = 'mysql:host=localhost;dbname=blog_test;port=3306;charset=utf8';
$pdo = new PDO($dns, 'root', '');
登入後複製

普通情況下,我們直接實例化的時候傳遞建構參數就可以得到一個 PDO 物件。這樣,我們就和資料庫建立了連線。如果連線失敗,也就是參數寫得有問題的時候,在實例化時直接就會報異常。

PDO 物件的參數包括 DNS 資訊、使用者名稱、密碼,另外還有一個參數就是可以設定 PDO 連線的一些屬性,我們將在後面看到它的使用。

dns 參數

PDO 建構參數的第一個參數是一個 DNS 字串。在這個字串中使用分號 ; 分隔不同的參數內容。它裡面可以定義的內容包括:

  • DSN prefix,也就是我們要連接的資料庫類型,MySQL 資料庫一般都是直接使用 mysql: 這樣來定義即可。

  • host,連接的位址,在這裡我們連接的是本地資料庫localhost

  • port,連接埠號,MySQL 預設為3306 ,可以不寫入

  • dbname,要連接的資料庫名稱

  • unix_socket,可以指定MySQL 的Unix Socket 檔案

  • #charset,連接的字元集

我們可以透過一個函數來查看目前PHP 環境中所支援的資料庫擴充有哪些:

print_r(PDO::getAvailableDrivers());exit;
// Array
// (
//     [0] => dblib
//     [1] => mysql
//     [2] => odbc
//     [3] => pgsql
//     [4] => sqlite
// )
登入後複製

PDO 物件屬性

PDO 建構參數的最後一個參數可以設定連接的一些屬性,例如:

$pdo = new PDO($dns, 'root', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
showPdoAttribute($pdo);
// ……
// PDO::ATTR_ERRMODE: 2
// ……
登入後複製

showPdoAttribute() 方法是我們自己封裝的一個展示所有連接屬性的函數。

// 显示pdo连接属性
function showPdoAttribute($pdo){
    $attributes = array(
        "DRIVER_NAME", "AUTOCOMMIT", "ERRMODE", "CASE", "CLIENT_VERSION", "CONNECTION_STATUS",
        "ORACLE_NULLS", "PERSISTENT", "SERVER_INFO", "SERVER_VERSION"
    );
    
    foreach ($attributes as $val) {
        echo "PDO::ATTR_$val: ";
        echo $pdo->getAttribute(constant("PDO::ATTR_$val")) . "\n";
    }
}
登入後複製

在這個函數中,我們使用 PDO 實例的 getAttribute() 方法來取得對應的屬性值。在沒有設定 PDO::ATTR_ERRMODE 時,它的預設值為 0 ,也就是 PDO::ERRMODE_SILENT 常數所對應的值。在上述程式碼中,我們將它設定為了 PDO::ERRMODE_EXCEPTION ,查看屬性輸出的結果就變成了 2 。

除了在建構子的參數中設定屬性外,我們也可以使用 PDO 實例的 setAttribute() 方法來設定 PDO 的屬性值。

pdo2 = new PDO($dns, 'root', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);

echo $pdo2->getAttribute(PDO::ATTR_DEFAULT_FETCH_MODE), PHP_EOL;
// 4

// 设置属性
$pdo2->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
echo $pdo2->getAttribute(PDO::ATTR_DEFAULT_FETCH_MODE), PHP_EOL;
// 2
登入後複製

在這段程式碼中,我們設定 PDO::ATTR_DEFAULT_FETCH_MODE 為 PDO::FETCH_ASSOC 。這樣,在使用這個 $pdo2 的連線進行查詢時,輸出的結果都會是以數組鍵值對形式傳回的內容。我們馬上就進入查詢方面相關函數的學習。

查詢語句

大多數情況下,使用PDO 我們都會用它的預處理能力來寫SQL 語句,一來是效能更好,二來是更加安全。不過我們今天先不講預處理方面的問題,還是以最原始的直接操作 SQL 語句的方式學習相關的一些函數。

普通查詢及遍歷

// 普通查询 - 遍历1
$stmt = $pdo->query('select * from zyblog_test_user limit 5');
foreach ($stmt as $row) {
    var_dump($row);
}

// array(8) {
//     ["id"]=>
//     string(3) "204"
//     [0]=>
//     string(3) "204"
//     ["username"]=>
//     string(5) "three"
//     [1]=>
//     string(5) "three"
//     ["password"]=>
//     string(6) "123123"
//     [2]=>
//     string(6) "123123"
//     ["salt"]=>
//     string(3) "ccc"
//     [3]=>
//     string(3) "ccc"
//   }
//   ……

// 普通查询 - 遍历2
$stmt = $pdo->query('select * from zyblog_test_user limit 5');

while ($row = $stmt->fetch()) {
    var_dump($row);
}

// array(8) {
//     ["id"]=>
//     string(3) "204"
//     [0]=>
//     string(3) "204"
//     ["username"]=>
//     string(5) "three"
//     [1]=>
//     string(5) "three"
//     ["password"]=>
//     string(6) "123123"
//     [2]=>
//     string(6) "123123"
//     ["salt"]=>
//     string(3) "ccc"
//     [3]=>
//     string(3) "ccc"
//   }
//   ……
登入後複製

PDO 實例的 query() 方法就是執行一條查詢語句,並傳回一個 PDOStatement 物件。透過遍歷這個對象,就可以獲得查詢出來的資料結果集。

在程式碼中,我們使用了兩種方式來遍歷,其實它們的效果都是一樣的。在這裡,我們要關注的是返回的資料格式。可以看出,資料是以數組格式傳回的,並且是以兩種形式,一個是資料庫定義的鍵名,一個是以下標形式。

查詢結果集(陣列、物件)

其實大部分情況下,我們只需要資料庫鍵名的那種鍵值對形式的資料就可以了。這個有兩種方式,一是直接使用上文中我們定義好預設 PDO::ATTR_DEFAULT_FETCH_MODE 屬性的 $pdo2 連接,另一個就是在查詢的時候為 query() 方法指定屬性。

$stmt = $pdo2->query('select * from zyblog_test_user limit 5');
foreach ($stmt as $row) {
    var_dump($row);
}
// array(4) {
//     ["id"]=>
//     string(1) "5"
//     ["username"]=>
//     string(3) "two"
//     ["password"]=>
//     string(6) "123123"
//     ["salt"]=>
//     string(3) "bbb"
//   }
//   ……

$stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_ASSOC);
foreach ($stmt as $row) {
    var_dump($row);
}
// array(4) {
//     ["id"]=>
//     string(1) "5"
//     ["username"]=>
//     string(3) "two"
//     ["password"]=>
//     string(6) "123123"
//     ["salt"]=>
//     string(3) "bbb"
//   }
//   ……
登入後複製

當然,我們也可以直接讓資料回傳成物件的格式,同樣的也是使用預先定義的常數來指定 query() 或 PDO 實例連接的屬性就可以了。

$stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_OBJ);
foreach ($stmt as $row) {
    var_dump($row);
}
// object(stdClass)#4 (4) {
//     ["id"]=>
//     string(1) "5"
//     ["username"]=>
//     string(3) "two"
//     ["password"]=>
//     string(6) "123123"
//     ["salt"]=>
//     string(3) "bbb"
//   }
//   ……
登入後複製

查詢結果集(類別)

上面傳回物件形式的結果集中的物件是 stdClass 類型,也就是 PHP 的預設類別類型。那我們是否可以自己定義一個類,然後在查詢完成後直接產生它的結果集呢?就是像是 ORM 框架一樣,完成資料到物件的對應。既然這麼說了,那當然是可以的啦,直接看程式碼。

class user
{
    public $id;
    public $username;
    public $password;
    public $salt;

    public function __construct()
    {
        echo 'func_num_args: ' . func_num_args(), PHP_EOL;
        echo 'func_get_args: ';
        var_dump(func_get_args());
    }
}

class user2
{

}
// 返回指定对象
$u = new user;
$stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_INTO, $u);
foreach ($stmt as $row) {
    var_dump($row);
}
// object(user)#3 (4) {
//     ["id"]=>
//     string(1) "5"
//     ["username"]=>
//     string(3) "two"
//     ["password"]=>
//     string(6) "123123"
//     ["salt"]=>
//     string(3) "bbb"
//   }
//   ……

// 空类测试
$u = new user2;
$stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_INTO, $u);
foreach ($stmt as $row) {
    var_dump($row);
}

// object(user2)#2 (4) {
//     ["id"]=>
//     string(1) "5"
//     ["username"]=>
//     string(3) "two"
//     ["password"]=>
//     string(6) "123123"
//     ["salt"]=>
//     string(3) "bbb"
//   }
//   ……
登入後複製

在这段代码中,我们定义了两个类,user 类有完整的和数据库字段对应的属性,还定义了一个构造方法(后面会用到)。而 user2 类则是一个空的类。通过测试结果来看,类的属性对于 PDO 来说并不重要。它会默认创建数据库查询到的字段属性,并将它赋值给对象。那么假如我们定义了一个 const 常量属性并给予相同的字段名称呢?大家可以自己尝试一下。

对于 user 和 user2 来说,我们将它实例化了并传递给了 query() ,并且指定了结果集格式为 PDO::FETCH_INTO ,这样就实现了获取对象结果集的能力。但是 PDO 远比你想象的强大,我们还可以直接用类模板来获取查询结果集。

// 根据类返回指定对象
$stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_CLASS, 'user', ['x1', 'x2']);
foreach ($stmt as $row) {
    var_dump($row);
}
// func_num_args: 2
// func_get_args: array(2) {
//   [0]=>
//   string(2) "x1"
//   [1]=>
//   string(2) "x2"
// }
// object(user)#4 (4) {
//   ["id"]=>
//   string(1) "5"
//   ["username"]=>
//   string(3) "two"
//   ["password"]=>
//   string(6) "123123"
//   ["salt"]=>
//   string(3) "bbb"
// }
// ……
登入後複製

query() 方法直接使用查询结果集模式为 PDO::FETCH_CLASS ,并传递一个类模板的名称,PDO 就会在当前代码中查找有没有对应的类模板,获得的每个结果都会实例化一次。在这里,我们又多了一个参数,最后一个参数是一个数组,并且给了两个元素。估计有不少小伙伴已经看出来了,这个参数是传递给类的构造方法的。记住,使用这个模式,每个元素都会实例化一次,结果集中的每个元素都是新创建的类(object(user2)#3,#号后面的数字是不同的对象句柄id),而 PDO::FETCH_INTO 则是以引用的形式为每个元素赋值(object(user2)#3,#号后面的数字是相同的对象句柄id)。也就是说,我们使用 PDO::FETCH_INTO 模式的时候,修改一个元素的值,其它的元素也会跟着改变,如果使用一个数组去记录遍历的元素值,最后数组的结果也会是相同的最后一个元素的内容。

$stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_INTO, $u);
$resArr = [];
foreach ($stmt as $row) {
    var_dump($row);
    $resArr[] = $row;
}
$resArr[0]->id = 55555;
print_r($resArr);
// Array
// (
//     [0] => user2 Object
//         (
//             [id] => 55555
//             [username] => two
//             [password] => 123123
//             [salt] => bbb
//         )

//     [1] => user2 Object
//         (
//             [id] => 55555
//             [username] => two
//             [password] => 123123
//             [salt] => bbb
//         )

//     [2] => user2 Object
//         (
//             [id] => 55555
//             [username] => two
//             [password] => 123123
//             [salt] => bbb
//         )

//     [3] => user2 Object
//         (
//             [id] => 55555
//             [username] => two
//             [password] => 123123
//             [salt] => bbb
//         )

//     [4] => user2 Object
//         (
//             [id] => 55555
//             [username] => two
//             [password] => 123123
//             [salt] => bbb
//         )

// )
登入後複製

如何解决这个问题呢?最简单的方式就是在数组赋值的时候加个 clone 关键字呗!

查询结果集(指定字段)

最后轻松一点,我们看下 query() 方法还可以指定查询的某一个字段。

// 只返回第几个字段
$stmt = $pdo->query('select * from zyblog_test_user limit 5', PDO::FETCH_COLUMN, 2);
foreach ($stmt as $row) {
    var_dump($row);
}
// string(32) "bbff8283d0f90625015256b742b0e694"
// string(6) "123123"
// string(6) "123123"
// string(6) "123123"
// string(6) "123123"
登入後複製

增、删、改操作

除了查询之外的操作,我们也可以使用 exec() 方法来执行其他一些相应的 SQL 语句。

增加操作

$count = $pdo->exec("insert into zyblog_test_user(`username`, `password`, `salt`) value('akk', 'bkk', 'ckk')");
$id = $pdo->lastInsertId();

var_dump($count); // int(1)
var_dump($id); // string(3) "205"
登入後複製

exec() 返回的是影响的行数,如果我们执行这一条 SQL ,返回的就是成功添加了一行数据。如果要获得新增加数据的 id ,就要使用 lastInserId() 方法来获取。

$count = $pdo->exec("insert into zyblog_test_user(`username`, `password`, `salt`) value('akk', 'bkk', 'ckk', 'dkk')");
// Fatal error: Uncaught PDOException: SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count doesn't match value count at row 1
登入後複製

执行错误的 SQL 语句,就像根据 PDO::ATTR_ERRMODE 属性的设置来返回错误信息。我们在最上面的实例化 PDO 代码中指定了错误形式是异常处理模式,所以这里直接就会报 PDOException 异常。

修改操作

// 正常更新
$count = $pdo->exec("update zyblog_test_user set `username`='aakk' where id='{$id}'");

var_dump($count); // int(1)

// 数据不变更新
$count = $pdo->exec("update zyblog_test_user set `username`='aakk' where id='{$id}'");
var_dump($count); // int(0)

// 条件错误更新
$count = $pdo->exec("update zyblog_test_user set `username`='aakk' where id='123123123123'");
var_dump($count); // int(0)
echo '===============', PHP_EOL;
登入後複製

同样的,在执行更新操作的时候,exec() 返回的也是受影响的行数。很多小伙伴会以这个进行判断是否更新成功,但如果数据没有修改,那么它返回的将是 0 ,SQL 语句的执行是没有问题的,逻辑上其实也没有问题。比如我们在后台打开了某条数据查看,然后并不想更新任何内容就直接点了提交,这时候不应该出现更新失败的提示。也就是说,在前端判断更新操作的时候,需要判断字段是否都有改变,如果没有改变的话那么不应该提示更新失败。这一点是业务逻辑上的考虑问题,如果你认为这样也是更新失败的话,那么这么报错也没有问题,一切以业务形式为主。

删除操作

$count = $pdo->exec("delete from zyblog_test_user where id = '{$id}'");
var_dump($count); // int(1)

// 条件错误删除
$count = $pdo->exec("delete from zyblog_test_user where id = '5555555555'");
var_dump($count); // int(0)
登入後複製

删除操作需要注意的问题和更新操作是一样的,那就是同样的 exec() 只是返回影响行数的问题,不过相对于更新操作来说,没有受影响的行数那肯定是删除失败的,没有数据被删除。同样的,这个失败的提示也请根据业务情况来具体分析。

总结

不学不知道,一学吓一跳吧,简简单的一个 PDO 的创建和语句执行竟然有这么多的内容。对于我们的日常开发来说,掌握这些原理能够避免很多莫名其妙的问题,比如上面 exec() 只是返回影响行数在业务开发中如何判断操作是否成功的问题就很典型。好了,这只是第一篇,后面的学习不要落下了哦!

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202008/source/PHP%E4%B8%AD%E7%9A%84PDO%E6%93%8D%E4%BD%9C%E5%AD%A6%E4%B9%A0%EF%BC%88%E4%B8%80%EF%BC%89%E5%88%9D%E5%A7%8B%E5%8C%96PDO%E5%8F%8A%E5%8E%9F%E5%A7%8BSQL%E8%AF%AD%E5%8F%A5%E6%93%8D%E4%BD%9C.php
登入後複製

推荐学习:php视频教程

以上是三分鐘帶你了解PHP中的初始化PDO及原始SQL語句操作的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

適用於 Ubuntu 和 Debian 的 PHP 8.4 安裝和升級指南 適用於 Ubuntu 和 Debian 的 PHP 8.4 安裝和升級指南 Dec 24, 2024 pm 04:42 PM

PHP 8.4 帶來了多項新功能、安全性改進和效能改進,同時棄用和刪除了大量功能。 本指南介紹如何在 Ubuntu、Debian 或其衍生版本上安裝 PHP 8.4 或升級到 PHP 8.4

如何設定 Visual Studio Code (VS Code) 進行 PHP 開發 如何設定 Visual Studio Code (VS Code) 進行 PHP 開發 Dec 20, 2024 am 11:31 AM

Visual Studio Code,也稱為 VS Code,是一個免費的原始碼編輯器 - 或整合開發環境 (IDE) - 可用於所有主要作業系統。 VS Code 擁有大量針對多種程式語言的擴展,可以輕鬆編寫

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

您如何在PHP中解析和處理HTML/XML? 您如何在PHP中解析和處理HTML/XML? Feb 07, 2025 am 11:57 AM

本教程演示瞭如何使用PHP有效地處理XML文檔。 XML(可擴展的標記語言)是一種用於人類可讀性和機器解析的多功能文本標記語言。它通常用於數據存儲

解釋PHP中的晚期靜態綁定(靜態::)。 解釋PHP中的晚期靜態綁定(靜態::)。 Apr 03, 2025 am 12:04 AM

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

php程序在字符串中計數元音 php程序在字符串中計數元音 Feb 07, 2025 pm 12:12 PM

字符串是由字符組成的序列,包括字母、數字和符號。本教程將學習如何使用不同的方法在PHP中計算給定字符串中元音的數量。英語中的元音是a、e、i、o、u,它們可以是大寫或小寫。 什麼是元音? 元音是代表特定語音的字母字符。英語中共有五個元音,包括大寫和小寫: a, e, i, o, u 示例 1 輸入:字符串 = "Tutorialspoint" 輸出:6 解釋 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。總共有 6 個元

什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? 什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? Apr 03, 2025 am 12:03 AM

PHP的魔法方法有哪些? PHP的魔法方法包括:1.\_\_construct,用於初始化對象;2.\_\_destruct,用於清理資源;3.\_\_call,處理不存在的方法調用;4.\_\_get,實現動態屬性訪問;5.\_\_set,實現動態屬性設置。這些方法在特定情況下自動調用,提升代碼的靈活性和效率。

PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

See all articles