PHP の mysqli, mysqlnd, pdo_mysql, PDO, libmysqlclient まとめ

PHP で MySQL を利用する時、通常は PHP 拡張モジュール(extension)を用いて接続します。

その時、 `mysqli`, `mysql`, `mysqlnd`, `pdo_mysql`, `PDO`, `libmysqlclient` といったわかりづらい名前の諸々があるので、ここでまとめておきます。

## 拡張モジュール

```ini:php.ini
extension=mbstring.so
```

こんな感じで設定を書くことで、ネイティブ C で記述された機能を PHP 上で利用出来るようになります。

PHP の実装よりも高速に動作するため、 MySQL との通信処理など処理速度がボトルネックになるようなものは拡張モジュールとして実装することで、処理速度の向上をしています。

## 拡張モジュール用ライブラリ

まず、 MySQL 拡張モジュールを実装する際にベースとされるライブラリがあります。

現状は `mysqlnd` と `libmysqlclient` のどちらかです。

[PHP: どのライブラリを選ぶか - Manual](https://www.php.net/manual/ja/mysqlinfo.library.choosing.php)

これらは、 PHP のコンパイル時に `--with-pdo-mysql=mysqlnd` などと指定して選ぶことが可能です。

### mysqlnd

[MySQL Native Driver](https://www.php.net/manual/ja/book.mysqlnd.php) が現在推奨されているネイティブライブラリで、デフォルトでこれが使われます。

`libmysqlclient` よりも様々な点で優れているため、こちらを選ぶことがほとんどのケースで最適です。

`mysqlnd` それ自体も PHP 拡張モジュールとして実装されているため、パフォーマンスも高いです。

### libmysqlclient

`mysqlnd` の前に MySQL チーム(現 Oracle)が作成した、 PHP 依存のない純粋な C 言語のライブラリです。

利用時に MySQL をインストールする必要があったり、 MySQL ライセンスのため PHP に同梱出来なかったりと欠点がいくつかあります。

サポート自体は継続されていますが、一般に利用することはほぼないでしょう。

## まとめ1

- `mysqlnd` と `libmysqlclient` は MySQL に接続するためのベースライブラリで選択可能
- 基本は `mysqlnd` を選択する

## mysql

単純に `mysql` と言った時は、大体 PHP 2.0 からある古い拡張モジュールのことを指します。

[mysql_connect](https://www.php.net/manual/ja/function.mysql-connect.php) 関数などを提供している extension ですが、 PHP 7 以降は利用出来ません。

なので、この拡張モジュールは新規開発では利用されないでしょう。そもそもトランザクションすらないので、実用性もありません。
超絶古い PHP 3 や 4 で開発されたプロダクトがまだ生きていて、保守しなければならない時に見かけることがあるかもしれない、くらいです。

## mysqli

`MySQL Improved` 拡張モジュールです。公式ではこの拡張モジュールが推奨されています。

```php

$mysqli = new mysqli("example.com", "user", "password", "database");
if ($mysqli->connect_errno) {
    echo "Failed to connect to MySQL: " . $mysqli->connect_error;
}

$res = $mysqli->query("SELECT 'choices to please everybody.' AS _msg FROM DUAL");
$row = $res->fetch_assoc();
echo $row['_msg'];
```

こんな感じで手軽にクエリを投げることが出来る API を提供しています。

`mysql` と似た API も提供しているので、移行も比較的楽に可能です。

## PDO

PHP の基本機能として、複数のデータベースアプリケーション(MySQL, sqlite, Oracle など...)間で出来るだけインターフェースを統一し、同じ PHP コードで別 DB にも投げれるようにした API 実装が [PDO](https://www.php.net/manual/ja/book.pdo.php) です。

これを使うことで、接続先のDB用のドライバを切り替えるだけで手軽に別の DB アプリケーションへ移行することが出来ます。
(実際に別の DB アプリケーションに移行することがあるのかはおいといて)

Laravel や CakePHP は PDO をラップして実装されているので、 `mysqli` 拡張モジュールを利用することは出来ません。
逆に、 Doctrine や CodeIgniter は `mysqli` を使うことも可能です。

PDO を利用するのであれば、 `extension=mysqli` として `mysqli` 拡張モジュールを有効にする必要はありません。

### pdo_mysql

`pdo_mysql` 拡張モジュールは、 PDO API で MySQL に接続するためのドライバです。

PDO を使って MySQL に接続したい場合はこの拡張モジュールを有効にする必要があります。

他にも、 `pdo_sqlite` `pdo_pgsql` などのドライバ拡張モジュールがあり、それらを有効にすることで PDO を通して接続可能になります。

## まとめ2

- `mysql` はもう使われない古い拡張モジュール
- `mysqli` は推奨されている拡張モジュール
- `pdo_mysql` は他の DB に繋ぐことも考えた抽象化層である `PDO` を一個挟んだ拡張モジュール

フレームワークや OR マッパーによってこの辺りは隠蔽されることがほとんどですが、実際に使われている拡張モジュールが何かを知ることは `php.ini` の設定や Dockerfile を書く時などで必要になってきます。これでもう間違わないで拡張モジュールを選べるようになったのではないでしょうか。

## 参考資料

- [PHP: MySQL - Manual](https://www.php.net/manual/ja/set.mysqlinfo.php)
- [PHP: 用語説明 - Manual](https://www.php.net/manual/ja/mysqlinfo.terminology.php)
- [PHP: どの API を使うか - Manual](https://www.php.net/manual/ja/mysqlinfo.api.choosing.php)
- [PHP: どのライブラリを選ぶか - Manual](https://www.php.net/manual/ja/mysqlinfo.library.choosing.php)
- [PHP: Overview - Manual](https://www.php.net/manual/ja/mysqli.overview.php)
- [PHP: はじめに - Manual](https://www.php.net/manual/ja/intro.mysqlnd.php)
- [PHP: PDO - Manual](https://www.php.net/manual/ja/book.pdo.php)