phpでデータベースにアクセス時にpdoをあまり使ったことなく、mysqliをよく使っていましたが、今回PDOをゴリゴリ使うことがあったのでまとめてみました。
php7.3でコードを書いた後にターミナルから実行して確認しています。
公式ではこちらの内容になります。
phpのpdoって?
php data objectsの略で、phpからデータベースにアクセスする時に使う機能になります。
php5.1からは標準で使えるようになっているようです。
データベースアクセスしてみる
データベースを用意する
アクセスするためのデータベースを用意します。
mysqlに接続して、下記のSQLを実行してデータベースを作成します。
CREATE DATABASE test_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
character setで文字コードをutf8mb4に指定して、データベースを作成しています。
アクセスしてみる
早速mysqlデータベースにアクセスしてみます。
下記の内容をpdo_test.phpで保存して実行してみました。
<?php
try
{
$database_handler = new PDO('mysql:host=localhost:3306;dbname=test_db;charset=utf8mb4', 'root', 'password');
}
catch (PDOException $e)
{
echo "DB接続に失敗しました。\n";
echo $e->getMessage() . "\n";
exit;
}
echo "OK.\n";
new PDOして、mysqlにアクセスするためのインスタンスを作成します。
データベースにアクセスできない場合はここで、エラーになります。
エラーになった場合は、try catchでキャッチして、エラー内容を出力して処理を終了しています。
PDOのコンストラクタについての公式ドキュメントはこちらです。
実行してみます。
$ php pdo_test.php
OK.
接続できたので、エラーにならずに「OK.」が表示されました。
テーブルを作成する(queryでSQL実行)
pdoのqueryメソッドを使ってみます。
テーブルを作成するcreate文を実行します。
下記の内容をpdo_create_test.phpで保存して実行してみました。
<?php
try
{
$database_handler = new PDO('mysql:host=localhost:3306;dbname=test_db;charset=utf8mb4', 'root', 'password');
}
catch (PDOException $e)
{
echo "DB接続に失敗しました。\n";
echo $e->getMessage() . "\n";
exit;
}
$result = $database_handler->query(<<<EOF
CREATE TABLE products(
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(255),
price BIGINT,
PRIMARY KEY (id)
)
EOF);
if($result) {
echo "テーブル作成に成功しました\n";
} else {
echo "テーブル作成に失敗しました\n";
}
データベースにアクセスした後に、PDOのインスタンス(データベースハンドラ)を使って、queryメソッドを呼び出しています。
queryメソッドにproductsテーブルを作成するcreate文を入れて実行しています。
queryメソッドは成功するとPDOStatementが返ってきて、
失敗すると、falseが返ってきます。
成功した場合は成功時のメッセージ・失敗の場合は失敗メッセージを出して終了しています。
実行してみます…
$ php pdo_create_test.php
テーブル作成に成功しました
テーブルが作成されました。
mysqlに接続して、確認するとテーブルが作成されています。
既にテーブルがあるので、2回目以降実行しても、下記のように失敗します。
$ php pdo_create_test.php
テーブル作成に失敗しました
prepareステートメントを使ってみる
prepareステートメントを使って、データの追加・更新・削除をやってみます。
データを追加する
作ったproductsテーブルにデータを追加してみます。
こんな感じのコードを書きました。
ファイルに渡した引数でデータを登録するようにしました。
pdo_prepare_add.phpという名前で保存して実行してみました。
<?php
try
{
$database_handler = new PDO('mysql:host=localhost:3306;dbname=test_db;charset=utf8mb4', 'root', 'password');
if ($statement = $database_handler->prepare("INSERT INTO products (name, price) VALUES(:name, :price)")) {
$statement->bindParam(":name", $argv[1]);
$statement->bindParam(":price", $argv[2]);
$execute = $statement->execute();
if ($execute) {
echo "登録に成功しました。\n";
} else {
echo "登録に失敗しました。\n";
}
}
}
catch (PDOException $e)
{
echo "DB接続に失敗しました。\n";
echo $e->getMessage() . "\n";
exit;
}
解説
PDOオブジェクトを作った後に、prepareを呼び出して、$statement変数でPDOStatementオブジェクトを受け取ります。
受け取った変数を使って、bindParamをそれぞれ呼び出して、受け取った引数をセットします。
最後にexecuteを呼び出して、sqlを実行します。(bindParamでパラメータの箇所が埋められて実行されます)
実行する
実行してみると…
$ php pdo_prepare_add.php りんご 100
登録に成功しました。
登録されました。
登録してテーブルを確認してみると、データが入っていることが確認できます。
id | name | price |
---|---|---|
1 | りんご | 100 |
データを取得する
productsテーブルのデータを全て取得して表示するコードを書いてみました。
pdo_prepare_get.phpという名前で保存しました。
<?php
try
{
$database_handler = new PDO('mysql:host=localhost:3306;dbname=test_db;charset=utf8mb4', 'root', 'password');
if ($statement = $database_handler->prepare("SELECT id, name, price FROM products")) {
$statement->execute();
$products = $statement->fetchAll(PDO::FETCH_ASSOC);
foreach ($products as $product) {
echo "{$product['name']}:{$product['price']}\n";
}
}
}
catch (PDOException $e)
{
echo "DB接続に失敗しました。\n";
echo $e->getMessage() . "\n";
exit;
}
解説
PDOオブジェクトを作った後に、prepareを呼び出して、PDOStatementオブジェクトを受け取ります。
今回はバインドするパラメータがないので(置き換えるパラメータなし)、そのままexecuteを呼び出して実行します。
executeした後に、statementオブジェクトのfetchAllメソッドを呼び出すとデータが取得できます。
fetchメソッドもあります。
fetchメソッドの方は1件のみの取得で、fetchAllは全件取得です。
実行する
実行してみると…
$ php pdo_prepare_get.php
りんご:100
ぶどう:180
みかん:110
データが取得されて表示されました。(3件登録済み)
データを更新する
データを更新するコードを書きました。
引数として、名前・値段・更新するIDを渡すと、指定したIDの行が更新されます。
pdo_prepare_update.phpという名前で保存して、実行してみました。
<?php
try
{
$database_handler = new PDO('mysql:host=localhost:3306;dbname=test_db;charset=utf8mb4', 'root', 'password');
if ($statement = $database_handler->prepare("UPDATE products set name = :name, price = :price where id = :id")) {
$statement->bindParam(":name", $argv[1]);
$statement->bindParam(":price", $argv[2]);
$statement->bindParam(":id", $argv[3]);
$execute = $statement->execute();
if ($execute) {
echo "更新に成功しました。\n";
} else {
echo "更新に失敗しました。\n";
}
}
}
catch (PDOException $e)
{
echo "DB接続に失敗しました。\n";
echo $e->getMessage() . "\n";
exit;
}
解説
実行するSQLが変わっただけで、書き方はデータ追加時と同じです。
PDOオブジェクトを作成した後にbindParamをそれぞれ呼び出して、受け取った引数をセットします。
その後executeメソッドで実行しています。
実行する
データが次の通りになっている時に
id | name | price |
---|---|---|
1 | りんご | 100 |
2 | ぶどう | 180 |
3 | みかん | 110 |
下記のように実行してみます。
$ php pdo_prepare_update.php ばなな 160 2
更新に成功しました。
更新されました。指定した2番目が変わりました!
id | name | price |
---|---|---|
1 | りんご | 100 |
2 | ばなな | 160 |
3 | みかん | 110 |
データを削除する
データを削除するコードを書きました。
pdo_prepare_delete.phpという名前で作成しました。
引数として、削除したいIDを指定します。
<?php
try
{
$database_handler = new PDO('mysql:host=localhost:3306;dbname=test_db;charset=utf8mb4', 'root', 'password');
if ($statement = $database_handler->prepare("DELETE FROM products WHERE id = :id")) {
$statement->bindParam(":id", $argv[1]);
$execute = $statement->execute();
if ($execute) {
echo "削除に成功しました。\n";
} else {
echo "削除に失敗しました。\n";
}
}
}
catch (PDOException $e)
{
echo "DB接続に失敗しました。\n";
echo $e->getMessage() . "\n";
exit;
}
解説
こちらもデータ追加・更新時と同じように処理しています。
PDOオブジェクトを作成した後にパラメータをバインドして、executeで実行しています。
実行する
データが次の通りになっている時に、2番目を指定して削除してみます。
id | name | price |
---|---|---|
1 | りんご | 100 |
2 | ばなな | 160 |
3 | みかん | 110 |
実行すると..
$ php pdo_prepare_delete.php 2
削除に成功しました。
削除されました!
id | name | price |
---|---|---|
1 | りんご | 100 |
3 | みかん | 110 |
トランザクション(transaction)を使ってみる
トランザクションを使った場合の処理を書いています。
pdo_transaction.phpという名前で作成しました。
<?php
try
{
$database_handler = new PDO('mysql:host=localhost:3306;dbname=test_db;charset=utf8mb4', 'root', 'password');
$database_handler->beginTransaction();
if ($statement = $database_handler->prepare("INSERT INTO products (name, price) VALUES(:name, :price)")) {
$statement->bindParam(":name", $argv[1]);
$statement->bindParam(":price", $argv[2]);
$execute = $statement->execute();
if ($execute) {
echo "登録に成功しました。\n";
} else {
echo "登録に失敗しました。\n";
}
echo "パラメータ1は{$argv[1]}\n";
echo "パラメータ2は{$argv[2]}\n";
if ($argv[1] == 'test') {
throw new Exception('testは商品名としてだめ!');
}
$database_handler->commit();
}
}
catch (PDOException $e)
{
echo "DB接続に失敗しました。\n";
echo $e->getMessage() . "\n";
$database_handler->rollBack();
exit;
}
catch (Exception $e)
{
echo "$e\n";
$database_handler->rollBack();
}
解説
トランザクジョンを使うとデータをテーブルに反映させるタイミングを制御できます。
commitメソッドが呼ばれるまでは、テーブルが更新されません。
エラーになって、rollBackメソッドが呼ばれるとテーブルを更新前の状態に戻してくれます、
6行目のbeginTransactionでトランザクションが開始されます。
ここからテーブルに反映された内容が、24行目のコミットで確定します。
エラーがthrowされた場合は、catchした箇所で、それぞれrollBackしています。
実行する
テーブルの状態が下記のようになっているときに
id | name | price |
---|---|---|
1 | りんご | 100 |
3 | みかん | 110 |
登録が成功するパラメータを渡します。
$ php pdo_transaction.php ぶどう 150
登録に成功しました。
パラメータ1はぶどう
パラメータ2は150
テーブルを参照すると追加されたことが確認できます。
id | name | price |
---|---|---|
1 | りんご | 100 |
3 | みかん | 110 |
4 | ぶどう | 150 |
商品名をtestにして、登録してみます。
$ php pdo_transaction.php test 999
登録に成功しました。
パラメータ1はtest
パラメータ2は999
Exception: testは商品名としてだめ! in /Users/hirano/pdoTest/pdo_transaction.php:22
Stack trace:
#0 {main}
22行目でexceptionがthrowされるため、rollbackされてデータが入ってないことが確認できます。
id | name | price |
---|---|---|
1 | りんご | 100 |
3 | みかん | 110 |
4 | ぶどう | 150 |
終わりに
長くなりましたが、簡単に今回pdoを使った操作を網羅してみました。
細かいオプションやデータの取り方もいろいろあるので、公式のドキュメントや他のサイトの情報も確認してみてください。
コメント