溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PHP怎么初始化PDO及原始SQL語(yǔ)句操作

發(fā)布時(shí)間:2021-06-16 13:49:15 來(lái)源:億速云 閱讀:175 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹了PHP怎么初始化PDO及原始SQL語(yǔ)句操作,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

目錄

    PDO 實(shí)例

    首先來(lái)看看一個(gè) PDO 實(shí)例是如何初始化的。

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

    普通情況下,我們直接實(shí)例化的時(shí)候傳遞構(gòu)造參數(shù)就可以獲得一個(gè) PDO 對(duì)象。這樣,我們就和數(shù)據(jù)庫(kù)建立了連接。如果連接失敗,也就是參數(shù)寫(xiě)得有問(wèn)題的時(shí)候,在實(shí)例化時(shí)直接就會(huì)報(bào)異常。

    PDO 對(duì)象的參數(shù)包括 DNS 信息、用戶名、密碼,另外還有一個(gè)參數(shù)就是可以設(shè)置 PDO 連接的一些屬性,我們將在后面看到它的使用。

    dns 參數(shù)

    PDO 構(gòu)造參數(shù)的第一個(gè)參數(shù)是一個(gè) DNS 字符串。在這個(gè)字符串中使用分號(hào) ; 分隔不同的參數(shù)內(nèi)容。它里面可以定義的內(nèi)容包括:

    • DSN prefix,也就是我們要連接的數(shù)據(jù)庫(kù)類(lèi)型,MySQL 數(shù)據(jù)庫(kù)一般都是直接使用 mysql: 這樣來(lái)定義即可。

    • host,連接的地址,在這里我們連接的是本地?cái)?shù)據(jù)庫(kù) localhost

    • port,端口號(hào),MySQL 默認(rèn)為 3306 ,可以不寫(xiě)

    • dbname,要連接的數(shù)據(jù)庫(kù)名稱

    • unix_socket,可以指定 MySQL 的 Unix Socket 文件

    • charset,連接的字符集

    我們可以通過(guò)一個(gè)函數(shù)來(lái)查看當(dāng)前 PHP 環(huán)境中所支持的數(shù)據(jù)庫(kù)擴(kuò)展都有哪些:

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

    PDO 對(duì)象屬性

    PDO 構(gòu)造參數(shù)的最后一個(gè)參數(shù)可以設(shè)置連接的一些屬性,如:

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

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

    // 顯示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";
        }
    }

    在這個(gè)函數(shù)中,我們使用 PDO 實(shí)例的 getAttribute() 方法來(lái)獲取相應(yīng)的屬性值。在沒(méi)有設(shè)置 PDO::ATTR_ERRMODE 時(shí),它的默認(rèn)值為 0 ,也就是 PDO::ERRMODE_SILENT 常量所對(duì)應(yīng)的值。在上述代碼中,我們將它設(shè)置為了 PDO::ERRMODE_EXCEPTION ,查看屬性輸出的結(jié)果就變成了 2 。

    除了在構(gòu)造函數(shù)的參數(shù)中設(shè)置屬性外,我們也可以使用 PDO 實(shí)例的 setAttribute() 方法來(lái)設(shè)置 PDO 的屬性值。

    pdo2 = new PDO($dns, 'root', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
    
    echo $pdo2->getAttribute(PDO::ATTR_DEFAULT_FETCH_MODE), PHP_EOL;
    // 4
    
    // 設(shè)置屬性
    $pdo2->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    echo $pdo2->getAttribute(PDO::ATTR_DEFAULT_FETCH_MODE), PHP_EOL;
    // 2

    在這段代碼中,我們?cè)O(shè)置 PDO::ATTR_DEFAULT_FETCH_MODE 為 PDO::FETCH_ASSOC 。這樣,在使用這個(gè) $pdo2 的連接進(jìn)行查詢時(shí),輸出的結(jié)果都會(huì)是以數(shù)組鍵值對(duì)形式返回的內(nèi)容。我們馬上就進(jìn)入查詢方面相關(guān)函數(shù)的學(xué)習(xí)。

    查詢語(yǔ)句

    大多數(shù)情況下,使用 PDO 我們都會(huì)用它的預(yù)處理能力來(lái)編寫(xiě) SQL 語(yǔ)句,一來(lái)是性能更好,二來(lái)是更加安全。不過(guò)我們今天先不講預(yù)處理方面的問(wèn)題,還是以最原始的直接操作 SQL 語(yǔ)句的方式學(xué)習(xí)相關(guān)的一些函數(shù)。

    普通查詢及遍歷

    // 普通查詢 - 遍歷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 實(shí)例的 query() 方法就是執(zhí)行一條查詢語(yǔ)句,并返回一個(gè) PDOStatement 對(duì)象。通過(guò)遍歷這個(gè)對(duì)象,就可以獲得查詢出來(lái)的數(shù)據(jù)結(jié)果集。

    在代碼中,我們使用了兩種方式來(lái)遍歷,其實(shí)它們的效果都是一樣的。在這里,我們要關(guān)注的是返回的數(shù)據(jù)格式??梢钥闯?,數(shù)據(jù)是以數(shù)組格式返回的,并且是以兩種形式,一個(gè)是數(shù)據(jù)庫(kù)定義的鍵名,一個(gè)是以下標(biāo)形式。

    查詢結(jié)果集(數(shù)組、對(duì)象)

    其實(shí)大部分情況下,我們只需要數(shù)據(jù)庫(kù)鍵名的那種鍵值對(duì)形式的數(shù)據(jù)就可以了。這個(gè)有兩種方式,一是直接使用上文中我們定義好默認(rèn) PDO::ATTR_DEFAULT_FETCH_MODE 屬性的 $pdo2 連接,另一個(gè)就是在查詢的時(shí)候?yàn)?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"
    //   }
    //   ……

    當(dāng)然,我們也可以直接讓數(shù)據(jù)返回成對(duì)象的格式,同樣的也是使用預(yù)定義的常量來(lái)指定 query() 或者 PDO 實(shí)例連接的屬性就可以了。

    $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"
    //   }
    //   ……

    查詢結(jié)果集(類(lèi))

    上面返回對(duì)象形式的結(jié)果集中的對(duì)象是 stdClass 類(lèi)型,也就是 PHP 的默認(rèn)類(lèi)類(lèi)型。那么我們是否可以自己定義一個(gè)類(lèi),然后在查詢完成后直接生成它的結(jié)果集呢?就是像是 ORM 框架一樣,完成數(shù)據(jù)到對(duì)象的映射。既然這么說(shuō)了,那當(dāng)然是可以的啦,直接看代碼。

    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
    {
    
    }
    // 返回指定對(duì)象
    $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"
    //   }
    //   ……
    
    // 空類(lèi)測(cè)試
    $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"
    //   }
    //   ……

    在這段代碼中,我們定義了兩個(gè)類(lèi),user 類(lèi)有完整的和數(shù)據(jù)庫(kù)字段對(duì)應(yīng)的屬性,還定義了一個(gè)構(gòu)造方法(后面會(huì)用到)。而 user2 類(lèi)則是一個(gè)空的類(lèi)。通過(guò)測(cè)試結(jié)果來(lái)看,類(lèi)的屬性對(duì)于 PDO 來(lái)說(shuō)并不重要。它會(huì)默認(rèn)創(chuàng)建數(shù)據(jù)庫(kù)查詢到的字段屬性,并將它賦值給對(duì)象。那么假如我們定義了一個(gè) const 常量屬性并給予相同的字段名稱呢?大家可以自己嘗試一下。

    對(duì)于 user 和 user2 來(lái)說(shuō),我們將它實(shí)例化了并傳遞給了 query() ,并且指定了結(jié)果集格式為 PDO::FETCH_INTO ,這樣就實(shí)現(xiàn)了獲取對(duì)象結(jié)果集的能力。但是 PDO 遠(yuǎn)比你想象的強(qiáng)大,我們還可以直接用類(lèi)模板來(lái)獲取查詢結(jié)果集。

    // 根據(jù)類(lèi)返回指定對(duì)象
    $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() 方法直接使用查詢結(jié)果集模式為 PDO::FETCH_CLASS ,并傳遞一個(gè)類(lèi)模板的名稱,PDO 就會(huì)在當(dāng)前代碼中查找有沒(méi)有對(duì)應(yīng)的類(lèi)模板,獲得的每個(gè)結(jié)果都會(huì)實(shí)例化一次。在這里,我們又多了一個(gè)參數(shù),最后一個(gè)參數(shù)是一個(gè)數(shù)組,并且給了兩個(gè)元素。估計(jì)有不少小伙伴已經(jīng)看出來(lái)了,這個(gè)參數(shù)是傳遞給類(lèi)的構(gòu)造方法的。記住,使用這個(gè)模式,每個(gè)元素都會(huì)實(shí)例化一次,結(jié)果集中的每個(gè)元素都是新創(chuàng)建的類(lèi)(object(user2)#3,#號(hào)后面的數(shù)字是不同的對(duì)象句柄id),而 PDO::FETCH_INTO 則是以引用的形式為每個(gè)元素賦值(object(user2)#3,#號(hào)后面的數(shù)字是相同的對(duì)象句柄id)。也就是說(shuō),我們使用 PDO::FETCH_INTO 模式的時(shí)候,修改一個(gè)元素的值,其它的元素也會(huì)跟著改變,如果使用一個(gè)數(shù)組去記錄遍歷的元素值,最后數(shù)組的結(jié)果也會(huì)是相同的最后一個(gè)元素的內(nèi)容。

    $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
    //         )
    
    // )

    如何解決這個(gè)問(wèn)題呢?最簡(jiǎn)單的方式就是在數(shù)組賦值的時(shí)候加個(gè) clone 關(guān)鍵字唄!

    查詢結(jié)果集(指定字段)

    最后輕松一點(diǎn),我們看下 query() 方法還可以指定查詢的某一個(gè)字段。

    // 只返回第幾個(gè)字段
    $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() 方法來(lái)執(zhí)行其他一些相應(yīng)的 SQL 語(yǔ)句。

    增加操作

    $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() 返回的是影響的行數(shù),如果我們執(zhí)行這一條 SQL ,返回的就是成功添加了一行數(shù)據(jù)。如果要獲得新增加數(shù)據(jù)的 id ,就要使用 lastInserId() 方法來(lái)獲取。

    $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

    執(zhí)行錯(cuò)誤的 SQL 語(yǔ)句,就像根據(jù) PDO::ATTR_ERRMODE 屬性的設(shè)置來(lái)返回錯(cuò)誤信息。我們?cè)谧钌厦娴膶?shí)例化 PDO 代碼中指定了錯(cuò)誤形式是異常處理模式,所以這里直接就會(huì)報(bào) PDOException 異常。

    修改操作

    // 正常更新
    $count = $pdo->exec("update zyblog_test_user set `username`='aakk' where id='{$id}'");
    
    var_dump($count); // int(1)
    
    // 數(shù)據(jù)不變更新
    $count = $pdo->exec("update zyblog_test_user set `username`='aakk' where id='{$id}'");
    var_dump($count); // int(0)
    
    // 條件錯(cuò)誤更新
    $count = $pdo->exec("update zyblog_test_user set `username`='aakk' where id='123123123123'");
    var_dump($count); // int(0)
    echo '===============', PHP_EOL;

    同樣的,在執(zhí)行更新操作的時(shí)候,exec() 返回的也是受影響的行數(shù)。很多小伙伴會(huì)以這個(gè)進(jìn)行判斷是否更新成功,但如果數(shù)據(jù)沒(méi)有修改,那么它返回的將是 0 ,SQL 語(yǔ)句的執(zhí)行是沒(méi)有問(wèn)題的,邏輯上其實(shí)也沒(méi)有問(wèn)題。比如我們?cè)诤笈_(tái)打開(kāi)了某條數(shù)據(jù)查看,然后并不想更新任何內(nèi)容就直接點(diǎn)了提交,這時(shí)候不應(yīng)該出現(xiàn)更新失敗的提示。也就是說(shuō),在前端判斷更新操作的時(shí)候,需要判斷字段是否都有改變,如果沒(méi)有改變的話那么不應(yīng)該提示更新失敗。這一點(diǎn)是業(yè)務(wù)邏輯上的考慮問(wèn)題,如果你認(rèn)為這樣也是更新失敗的話,那么這么報(bào)錯(cuò)也沒(méi)有問(wèn)題,一切以業(yè)務(wù)形式為主。

    刪除操作

    $count = $pdo->exec("delete from zyblog_test_user where id = '{$id}'");
    var_dump($count); // int(1)
    
    // 條件錯(cuò)誤刪除
    $count = $pdo->exec("delete from zyblog_test_user where id = '5555555555'");
    var_dump($count); // int(0)

    刪除操作需要注意的問(wèn)題和更新操作是一樣的,那就是同樣的 exec() 只是返回影響行數(shù)的問(wèn)題,不過(guò)相對(duì)于更新操作來(lái)說(shuō),沒(méi)有受影響的行數(shù)那肯定是刪除失敗的,沒(méi)有數(shù)據(jù)被刪除。同樣的,這個(gè)失敗的提示也請(qǐng)根據(jù)業(yè)務(wù)情況來(lái)具體分析。

    感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“PHP怎么初始化PDO及原始SQL語(yǔ)句操作”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI