# PHP PDO 教程

> 原文： [https://zetcode.com/php/pdo/](https://zetcode.com/php/pdo/)

在本教程中，我们展示了如何在 PHP PDO 中对数据库进行编程。

## PHP PDO

PHP 数据对象（PDO）定义了用于访问 PHP 中数据库的轻量级接口。 它提供了一个数据访问抽象层，用于在 PHP 中使用数据库。 它定义了用于各种数据库系统的一致 API。

## PHP PDO 类

`PDO`表示 PHP 与数据库服务器之间的连接。 `PDOStatement`代表准备好的语句，在执行该语句后，代表关联的结果集。 `PDOException`表示 PDO 引发的错误。

## MySQL 数据库

在本教程中，我们将使用 MySQL 数据库。

`countries_mysql.sql`

```php
DROP TABLE IF EXISTS countries;
CREATE TABLE countries(id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, 
    name VARCHAR(255), population INT);

INSERT INTO countries(name, population) VALUES('China', 1382050000);
INSERT INTO countries(name, population) VALUES('India', 1313210000);
INSERT INTO countries(name, population) VALUES('USA', 324666000);
INSERT INTO countries(name, population) VALUES('Indonesia', 260581000);
INSERT INTO countries(name, population) VALUES('Brazil', 207221000);
INSERT INTO countries(name, population) VALUES('Pakistan', 196626000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Bangladesh', 162099000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Russia', 146838000);
INSERT INTO countries(name, population) VALUES('Japan', 126830000);

```

这些 SQL 命令创建一个`countries`表。

## PHP PDO 查询

PDO `query()`在单个函数调用中执行一条 SQL 语句，返回该语句返回的结果集（如果有）。

`version.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

$pdo = new PDO($dsn, $user, $passwd);

$stm = $pdo->query("SELECT VERSION()");

$version = $stm->fetch();

echo $version[0] . PHP_EOL;

```

该示例返回 MySQL 的版本。

```php
$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

```

这些变量用于创建到数据库的连接字符串。 `dsn`是数据源名称，其中包含连接到数据库所需的信息。

```php
$pdo = new PDO($dsn, $user, $passwd);

```

创建一个新的`PDO`对象。 我们向构造函数传递数据源名称以及用户名和密码。 `PDO`类表示 PHP 与数据库服务器之间的连接。

```php
$stm = $pdo->query("SELECT VERSION()");

```

`query()`方法在单个函数调用中执行一条 SQL 语句。 它返回结果集。

```php
$version = $stm->fetch();

```

PDO 语句的`fetch()`方法从结果集中获取下一行。 在我们的例子中，它是 MySQL 的一个版本。

```php
echo $version[0] . PHP_EOL;

```

`$version`是一个数组； 我们得到它的第一价值。

```php
$ php version.php
5.7.22-0ubuntu0.16.04.1

```

这是输出。

## PHP PDO 执行

PDO `exec()`执行一条 SQL 语句并返回受影响的行数。

`affected_rows.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

$pdo = new PDO($dsn, $user, $passwd);

$id = 12;

$nrows = $pdo->exec("DELETE FROM countries WHERE id IN (1, 2, 3)");

echo "The statement affected $nrows rows\n";

```

该代码示例将删除三行。 它打印受影响的行数。

```php
$nrows = $pdo->exec("DELETE FROM countries WHERE id IN (1, 2, 3)");

```

在此 SQL 语句中，我们删除 ID 为 1、2 和 3 的行。已删除的行数存储在`$nrows`变量中。

```php
echo "The statement deleted $nrows rows\n";

```

我们打印已删除的行数。

## PHP PDO 提取样式

提取样式参数控制如何将下一行返回给调用方。 例如，`PDO::FETCH_ASSOC`返回按列名索引的数组，`PDO::FETCH_NUM`返回按列号索引的数组，`PDO::FETCH_BOTH`返回按列名和索引列号索引的数组。 默认的获取样式为`PDO::FETCH_BOTH`。

`fetch_style_num.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

$pdo = new PDO($dsn, $user, $passwd);

$stm = $pdo->query("SELECT * FROM countries");

$rows = $stm->fetchAll(PDO::FETCH_NUM);

foreach($rows as $row) {

    printf("$row[0] $row[1] $row[2]\n");
}

```

在此代码示例中，我们在索引数组中获取数据。

```php
$stm = $pdo->query("SELECT * FROM countries");

```

我们从`countries`表中选择所有数据。

```php
$rows = $stm->fetchAll(PDO::FETCH_NUM);

```

我们将`PDO:FETCH_NUM`样式传递给`fetchAll()`方法。

```php
foreach($rows as $row) {

    printf("$row[0] $row[1] $row[2]\n");
}

```

我们遍历`$rows`数组并打印字段。 通过数组索引访问这些字段。

`fetch_style_assoc.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

$pdo = new PDO($dsn, $user, $passwd);

$stm = $pdo->query("SELECT * FROM countries");

$rows = $stm->fetchAll(PDO::FETCH_ASSOC);

foreach($rows as $row) {

    printf("{$row['id']} {$row['name']} {$row['population']}\n");
}

```

在此示例中，我们以关联数组的形式获取数据。

```php
$rows = $stm->fetchAll(PDO::FETCH_ASSOC);

```

在`fetchAll()`方法中，我们使用`PDO::FETCH_ASSOC`样式。

## PHP PDO 参数绑定

SQL 语句通常是动态构建的。 用户提供一些输入，并且此输入已内置到语句中。 每当我们处理来自用户的输入时，我们都必须谨慎。 它具有一些严重的安全隐患。 动态构建 SQL 语句的推荐方法是使用参数绑定。

PDO 包含`bindParam()`和`bindValue()`方法来创建参数化查询。

PDO 允许将数据绑定到问号或命名的占位符。

`parameterized_query.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "root";
$passwd = "andrea";

$pdo = new PDO($dsn, $user, $passwd);

$id = 12;

$stm = $pdo->prepare("SELECT * FROM countries WHERE id = ?");
$stm->bindValue(1, $id);
$stm->execute();

$row = $stm->fetch(PDO::FETCH_ASSOC);

echo "Id: " . $row['id'] . PHP_EOL;
echo "Name: " . $row['name'] . PHP_EOL;
echo "Population: " . $row['population'] . PHP_EOL;

```

在示例中，我们使用`bindValue()`创建参数化查询。 我们使用问号占位符。

```php
$id = 12;

```

说此输入来自用户。

```php
$stm = $pdo->prepare("SELECT * FROM countries WHERE id = ?");
$stm->bindValue(1, $id);
$stm->execute();

```

`select`语句从表中获取特定行。 我们将带有`bindValue()`的值绑定到问号占位符。

在第二种情况下，我们使用`bindParam()`。

`parameterized_query2.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

$pdo = new PDO($dsn, $user, $passwd);

$id = 12;

$stm = $pdo->prepare("SELECT * FROM countries WHERE id = :id");
$stm->bindParam(":id", $id, PDO::PARAM_INT);
$stm->execute();

$row = $stm->fetch(PDO::FETCH_ASSOC);

echo "Id: " . $row['id'] . PHP_EOL;
echo "Name: " . $row['name'] . PHP_EOL;
echo "Population: " . $row['population'] . PHP_EOL;

```

该示例选择并打印特定的行。

```php
$stm = $pdo->prepare("SELECT * FROM countries WHERE id = :id");
$stm->bindParam(":id", $id, PDO::PARAM_INT);
$stm->execute();

```

这次我们使用命名占位符（`:id`）和`bindParam()`。

## PHP PDO 最后插入的行 ID

PDO `lastInsertId()`方法返回最后插入的行 ID。

`create_table.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

$pdo = new PDO($dsn, $user, $passwd);

$sql = "CREATE TABLE words(id INT PRIMARY KEY AUTO_INCREMENT,
    word VARCHAR(255))";

$ret = $pdo->exec($sql);
$pdo->exec("INSERT INTO words(word) VALUES ('pen')");
$pdo->exec("INSERT INTO words(word) VALUES ('bum')");
$pdo->exec("INSERT INTO words(word) VALUES ('hum')");
$pdo->exec("INSERT INTO words(word) VALUES ('den')");

$rowid = $pdo->lastInsertId();

echo "The last inserted row id is: $rowid\n";

```

在示例中，我们创建一个新表。 创建表后，我们用`lastInsertId()`找出最后插入的 ID。

```php
$ php create_table.php
The last inserted row id is: 4

```

This is the output.

```php
mysql> select * from words;
+----+------+
| id | word |
+----+------+
|  1 | pen  |
|  2 | bum  |
|  3 | hum  |
|  4 | den  |
+----+------+
4 rows in set (0.01 sec)

```

我们验证数据。

## PHP PDO 事务

事务是针对一个或多个数据库中数据的数据库操作的基本单位。 事务中所有 SQL 语句的影响可以全部提交给数据库，也可以全部回滚。

PDO `beginTransaction()`启动新事务。 PDO `commit()`提交事务。 PDO `rollback()`将回滚事务。

`transaction.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

$pdo = new PDO($dsn, $user, $passwd);

try {

    $pdo->beginTransaction();
    $stm = $pdo->exec("INSERT INTO countries(name, population) VALUES ('Iraq', 38274000)");
    $stm = $pdo->exec("INSERT INTO countries(name, population) VALUES ('Uganda', 37673800)");

    $pdo->commit();

} catch(Exception $e) {

    $pdo->rollback();
    throw $e;
}

```

在示例中，我们将两个新的国家/地区添加到数据库表中。 将`insert`语句放置在事务中：要么执行两个插入，要么都不执行。

```php
} catch(Exception $e) {

    $pdo->rollback();
    throw $e;
}

```

如果发生异常，我们回滚事务：没有数据写入数据库。 我们抛出异常，以便异常处理继续按常规方式进行。

## PHP PDO 获取元数据

元数据是有关数据库中数据的信息。 元数据包含有关我们存储数据的表和列的信息。 SQL 语句影响的行数是元数据。 结果集中返回的行数和列数也是元数据。

`column_count.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

$pdo = new PDO($dsn, $user, $passwd);

$stm = $pdo->query("SELECT name, population FROM countries WHERE id=1");

$ncols = $stm->columnCount();

echo "The result set contains $ncols columns\n";

```

在示例中，我们使用`columnCount()`方法打印结果集中的列数。

`getAttribute()`方法检索数据库连接属性。

`connection_attributes.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

$pdo = new PDO($dsn, $user, $passwd);

$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
$server_version = $pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
$autocommit_mode = $pdo->getAttribute(PDO::ATTR_AUTOCOMMIT);

echo "Driver: $driver\n";
echo "Server version: $server_version\n";
echo "Autocommit mode: $autocommit_mode\n";

```

在示例中，我们使用`getAttribute()`方法获取驱动程序名称，服务器版本和自动提交模式。

```php
$ php connection_attributes.php
Driver: mysql
Server version: 5.7.22-0ubuntu0.16.04.1
Autocommit mode: 1

```

这是一个示例输出。

在以下示例中，我们打印列元数据。 列元数据通过`getColumnMeta()`方法检索。

`column_metadata.php`

```php
<?php

$dsn = "mysql:host=localhost;dbname=mydb";
$user = "user12";
$passwd = "12user";

$pdo = new PDO($dsn, $user, $passwd);

$stm = $pdo->query("SELECT * FROM countries WHERE id=1");

$col_meta = $stm->getColumnMeta(0);

echo "Table name: {$col_meta["table"]}\n";
echo "Column name: {$col_meta["name"]}\n";
echo "Column length: {$col_meta["len"]}\n";
echo "Column flags: {$col_meta["flags"][0]} {$col_meta["flags"][1]} \n";

```

在示例中，我们获取列表，名称，长度和标志。

```php
$ php column_metadata.php
Table name: countries
Column name: id
Column length: 20
Column flags: not_null primary_key

```

This is a sample output.

您可能也对以下相关教程感兴趣： [PHP SQLite3 教程](/php/sqlite3/)， [CakePHP 数据库教程](/php/cakephpdatabase/)， [Doctrine `QueryBuilder`教程](/doctrine/querybuilder/)， [PHP 文件系统函数](/articles/phpfilesystemfunctions/) ， [Twig 教程](/php/twig/)， [PHP Faker 教程](/php/faker/)， [PHP 教程](/lang/php/)或列出[所有 PHP 教程](/all/#php)。

在本教程中，我们使用 PHP PDO 处理 MySQL 数据库。