📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

 
(同じ利用者による、間の11版が非表示)
133行目: 133行目:


== データベースの接続 ==
== データベースの接続 ==
==== 接続文字列 ====
PDOクラスのインスタンスを作成することにより、接続が確立される。<br>
PDOクラスのインスタンスを作成することにより、接続が確立される。<br>
コンストラクタには、データソース(DSN)、ユーザ名、パスワードを指定する。<br>
コンストラクタには、データソース(DSN)、ユーザ名、パスワードを指定する。<br>
156行目: 157行目:
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  $<PDOクラスのインスタンス名> = new PDO(<データソース名>, <データベースユーザ名>, <パスワード>, <ドライバオプション>);
  $<PDOクラスのインスタンス名> = new PDO(<データソース名>, <データベースユーザ名>, <パスワード>, <ドライバオプション>);
PDO PDO::__construct ( string dsn
                        [, string username
                        [, string password
                        [, array driver_options]]] )
指定されたデータベースへの接続を表すPDOインスタンスを生成します。
引数:
  dsn
    データソース名(Data Source Name)またはDSN。データベースに接続するために必要な情報が含まれる。
  username
    DSN文字列のユーザ名。このパラメータは、いくつかのPDOドライバではオプションである。
  password
    パスワード。
    DSN文字列で必要とされる場合に指定。
  driver_options
    ドライバ固有の接続オプションを指定するキー=> 値の配列
戻り値:
  成功時にPDOオブジェクトを返す。
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
196行目: 221行目:
*: 値は予め用意されている定数以外に、論理値や文字列等の一般的な値でもよい。
*: 値は予め用意されている定数以外に、論理値や文字列等の一般的な値でもよい。
<br>
<br>
以下に、よく使用されるドライバオプションとその値を示す。<br>
==== ドライバオプション ====
ドライバオプションとその値を以下に示す。<br>
<br>
<syntaxhighlight lang="php">
// ドライバオプションの使用例
$options = [
    // エラー発生時に例外をスロー
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    // フェッチモードをデフォルトで連想配列に設定
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    // プリペアドステートメントを有効化
    PDO::ATTR_EMULATE_PREPARES => false,
    // 持続的な接続を無効化
    PDO::ATTR_PERSISTENT => false,
    // カラム名を小文字に変換
    PDO::ATTR_CASE => PDO::CASE_LOWER
];
$db = new PDO(
    'mysql:host=localhost;dbname=sampledb;charset=utf8mb4',
    'root',
    'root',
    $options
);
</syntaxhighlight>
<br>
* PDO::ATTR_ERRMODE
* PDO::ATTR_ERRMODE
*: クエリの実行でエラーが起こった場合、どのように処理をするかを指定する。
*: エラーレポートの方法を設定するための属性である。
*: クエリの実行でエラーが起きた場合、どのように処理をするかを指定する。
*: 初期値は、<code>PDO::ERRMODE_SILENT</code>である。
*: 初期値は、<code>PDO::ERRMODE_SILENT</code>である。
** PDO::ERRMODE_EXCEPTION
** PDO::ERRMODE_EXCEPTION
**: 例外をスローする。
**: エラーが発生した時に例外 (PDOException例外クラス) をスローする。
**: エラーを例外としてキャッチできるようになり、デバッグが容易になる。
** PDO::ERRMODE_WARNING
** PDO::ERRMODE_WARNING
**: クエリの実行Lで発生したエラーをPHPのWarningとして報告する。
**: クエリの実行Lで発生したエラーをPHPのWarningとして報告する。
210行目: 267行目:
*: <br>
*: <br>
* PDO::ATTR_DEFAULT_FETCH_MODE
* PDO::ATTR_DEFAULT_FETCH_MODE
*: <code>PDOStatement::fetch</code>メソッドや<code>PDOStatement::fetchAll</code>メソッドで引数が省略された場合、または、
*: SELECT結果を連想配列で取得できる。
*: ステートメントが<code>foreach</code>文に直接かけられた場合のフェッチスタイルを設定する。
*: キーがカラム名になるため、データアクセスが直観的になる。
*: <br>
*: <code>PDOStatement::fetch</code>メソッドや<code>PDOStatement::fetchAll</code>メソッドで引数が省略された場合、
*: または、ステートメントが<code>foreach</code>文に直接かけられた場合のフェッチスタイルを設定する。
*: 初期値は、<code>PDO::FETCH_BOTH</code>である。
*: 初期値は、<code>PDO::FETCH_BOTH</code>である。
** PDO::FETCH_BOTH
** PDO::FETCH_BOTH
225行目: 285行目:
*: データベース側が持つプリペアドステートメント機能のエミュレーションをPDO側で行うかどうかを設定する。
*: データベース側が持つプリペアドステートメント機能のエミュレーションをPDO側で行うかどうかを設定する。
*: PHP 5.2以降の初期値は<code>true</code>である。
*: PHP 5.2以降の初期値は<code>true</code>である。
*: <br>
*: <code>false</code>の場合、ネイティブのプリペアドステートメントを使用する。
*: これは、SQLインジェクション対策として有効であり、また、クエリのパフォーマンスが向上する。
*: <br>
*: この設定は、いくつかPDOの挙動に違いが現れる。
*: この設定は、いくつかPDOの挙動に違いが現れる。
** プリペアドステートメントのためにデータベースと通信する必要が無くなるため、エミュレーションを行う方がパフォーマンスは向上する。
*: エミュレーションを行う場合、プリペアドステートメントのためにデータベースと通信する必要が無くなるため、パフォーマンスは向上する。
** 存在しないテーブル名やカラム名をクエリに持つプリペアドステートメントを発行する場合、<br>エミュレーションを行わない場合はすぐにエラーが発生するが、エミュレーションを行う場合はクエリを実行するまでエラーが発生するかどうかわからない。
*: 存在しないテーブル名 / カラム名をクエリに持つプリペアドステートメントを発行する場合、
*: エミュレーションを行わない場合は即エラーが発生するが、エミュレーションを行う場合はクエリを実行するまでエラーが発生するかどうかわからない。
** エミュレーションを行う場合のみ、<code>;</code>(セミコロン)区切りで複数のクエリを1つのクエリで実行することができる。
** エミュレーションを行う場合のみ、<code>;</code>(セミコロン)区切りで複数のクエリを1つのクエリで実行することができる。
*: <br>
*: <br>
* PDO::ATTR_PERSISTENT(コンストラクタでの指定のみ)
* PDO::ATTR_PERSISTENT (コンストラクタでの指定のみ)
*: <code>true</code>の場合、PHPスクリプトが終了してもデータベースへの接続を維持して、次回に再利用する。
*: <code>true</code>の場合、PHPスクリプトが終了してもデータベースへの接続を維持して、次回に再利用する。
*: 特に、大規模システムでは恩恵が大きい。
*: 特に、大規模システムでは恩恵が大きい。
*: <br>
*: <code>false</code>の場合は、持続的な接続を無効化する。
*: メモリ管理の観点から、通常は無効にすることを推奨する。
*: <br>
*: <br>
* PDO::MYSQL_ATTR_USE_BUFFERED_QUERY(MySQL専用)
* PDO::MYSQL_ATTR_USE_BUFFERED_QUERY(MySQL専用)
247行目: 315行目:
* PDO::MYSQL_ATTR_INIT_COMMAND(MySQL専用、コンストラクタでの指定のみ)
* PDO::MYSQL_ATTR_INIT_COMMAND(MySQL専用、コンストラクタでの指定のみ)
*: データベースに接続した直後に実行されるクエリをここに記述する。
*: データベースに接続した直後に実行されるクエリをここに記述する。
*: <br>
* PDO::ATTR_CASE
*: <code>PDO::CASE_LOWER</code>を指定する場合、カラム名を小文字に統一する。
*: そのため、一貫性のあるコーディングが可能になる。
<br>
<br>
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
306行目: 378行目:
<u>データベースに接続できない場合等は、Warningが発生する。</u><br>
<u>データベースに接続できない場合等は、Warningが発生する。</u><br>
<u>もし、データベースを動的に指定する場合、<code>set_error_handler</code>関数を使用して<code>ErrorException</code>に変換した後、例外処理を行う。</u><br>
<u>もし、データベースを動的に指定する場合、<code>set_error_handler</code>関数を使用して<code>ErrorException</code>に変換した後、例外処理を行う。</u><br>
<br>
==== 文字コードの設定 ====
<u>PDOでMySQLに接続する場合は、文字コードの設定 (例: charset=utf8mb4) を指定することを強く推奨する。</u><br>
<br>
もし、明示的に指定しない場合、MySQLのデフォルト設定に依存することになり、環境によって動作が異なる可能性がある。<br>
そのため、確実な文字エンコーディングの制御のために、charsetを明示的に指定することを推奨する。<br>
<br>
* 絵文字や特殊文字のサポート
*: utf8mb4は絵文字やその他の4バイト文字を完全にサポートする。
*: 通常のutf8では絵文字などが正しく保存できない可能性がある。
*: <br>
* 文字化け防止
*: 日本語を含む多言語対応において、文字化けを防ぐことができる。
*: データベースとアプリケーション間で一貫した文字エンコーディングを保証する。
*: <br>
* 将来の互換性
*: 現代のWebアプリケーションでは、utf8mb4が事実上の標準となっている。
*: 後々データベースに絵文字等を格納する可能性を考慮すると、最初から設定しておくのが無難である。
<br>
<syntaxhighlight lang="php">
// 使用例
$db = new PDO('mysql:host=<IPアドレスまたはホスト名>;dbname=<データベース名>;charset=utf8mb4', '<ユーザ名>', '<パスワード>');
</syntaxhighlight>
<br><br>
<br><br>


335行目: 432行目:
データベースの接続は、PHPスクリプトが終了しても閉じられずにキャッシュされ、他のPHPスクリプトが同じ内容の接続を要求する時に再利用される。<br>
データベースの接続は、PHPスクリプトが終了しても閉じられずにキャッシュされ、他のPHPスクリプトが同じ内容の接続を要求する時に再利用される。<br>
このキャッシュにより、新しい接続を確立するオーバーヘッドを避けることができるため、Webアプリケーションを高速化できるようになる。<br>
このキャッシュにより、新しい接続を確立するオーバーヘッドを避けることができるため、Webアプリケーションを高速化できるようになる。<br>
<br>
もし、明示的に閉じる場合、作成したPDOクラスのオブジェクトにNULLを代入する。<br>
  <syntaxhighlight lang="php">
  <syntaxhighlight lang="php">
  <?php
  <?php
     $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass,
     try
                  [
    {
                      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
      $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass,
                      PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
                      [
                  ]);
                        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
   
                        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    foreach($dbh->query('SELECT * from FOO') as $row)
                      ]);
      foreach($dbh->query('SELECT * from FOO') as $row)
      {
          print_r($row);
      }   
    }
    catch (PDOException $e)
     {
     {
       print_r($row);
       print('Connection failed:'.$e->getMessage());
     }  
      die();
     }
   
   
     // データベースの切断
     // データベースの切断
    $sth = null;
     $dbh = null;
     $dbh = null;
  ?>
  ?>
500行目: 606行目:
       $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
       $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   
   
      // トランザクション開始
       $dbh->beginTransaction();
       $dbh->beginTransaction();
      // SQLクエリの実行
       $dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
       $dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
       $dbh->exec("insert into salarychange (id, amount, changedate) values (23, 50000, NOW())");
       $dbh->exec("insert into salarychange (id, amount, changedate) values (23, 50000, NOW())");
      // 正常に実行できた場合はコミット
       $dbh->commit();
       $dbh->commit();
     }
     }
     catch(Exception $e)
     catch(Exception $e)
     {
     {
       $dbh->rollBack();
       // エラーが発生した場合はロールバック
      if ($dbh->inTransaction()) {
          $dbh->rollBack();
      }
       echo "失敗しました。" . $e->getMessage();
       echo "失敗しました。" . $e->getMessage();
     }
     }
531行目: 645行目:
<br>
<br>
プリペアドステートメントは、データベースの種類や機能に関わらず同じ仕組みで データベースへのアクセスができる。<br>
プリペアドステートメントは、データベースの種類や機能に関わらず同じ仕組みで データベースへのアクセスができる。<br>
<br><br>
== プリペアドステートメントの種類 ==
==== bindValueメソッド (値渡し) ====
* メリット
*: バインドした後に元の変数が変更されても影響を受けない。
*: 直接リテラル値をバインドできる。
*: メモリ効率が良い。 (参照を保持しない)
* デメリット
*: ループ内で変数を変更して再実行する場合は、その都度、bindValueメソッドが必要となる。
<br>
<syntaxhighlight lang="php">
$value = 100;
$stmt->bindValue(1, $value, PDO::PARAM_INT);
$value = 200;      // この変更はSQLに影響しない
$stmt->execute();  // 100 が使用される
</syntaxhighlight>
<br>
==== bindParamメソッド (参照渡し) ====
* メリット
*: 変数の参照を保持するので、値を変更して再実行が容易
*: ストアドプロシージャのOUTパラメータで使用可能
* デメリット
*: リテラル値を直接バインドできない。
*: メモリを若干多く使用する。 (参照を保持するため)
<br>
<syntaxhighlight lang="php">
$value = 100;
$stmt->bindParam(1, $value, PDO::PARAM_INT);
$value = 200;      // この変更がSQLに反映される
$stmt->execute();  // 200 が使用される
</syntaxhighlight>
<br>
==== executeメソッドで直接記述 ====
* メリット
*: コードが簡潔
*: 1回のみ使用する場合は効率的
*: <br>
* デメリット
*: 変数の値を後から変更して再実行する場合は、その都度配列を作る必要がある。
*: 参照渡しができない。
<br>
<syntaxhighlight lang="php">
$stmt = $pdo->prepare("UPDATE student SET id = ?, name = ?, grade = ? WHERE id = ?");
$stmt->execute([$id, $name, $grade, $old_id]);  // シンプル!
## 1回限りのクエリの場合、executeメソッド
$stmt->execute([$id, $name, $grade]);
</syntaxhighlight>
<br>
==== 使い分け ====
<syntaxhighlight lang="php">
# 使い分け
## 一般的なケースでは、bindValueメソッドを使用
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bindValue(1, $id, PDO::PARAM_INT);
$stmt->execute();
## 以下に示す場合は、bindParamメソッドを使用
## ループ内で値を変更しながら実行する場合
## ループ内で変数を変更しながら再実行する場合
## ストアドプロシージャのOUTパラメータを使用する場合
## 特別な理由で参照渡しが必要な場合
$stmt = $pdo->prepare("INSERT INTO logs (user_id, action) VALUES (?, ?)");
$stmt->bindParam(1, $user_id, PDO::PARAM_INT);
$stmt->bindParam(2, $action, PDO::PARAM_STR);
foreach($actions as $action) {
    $stmt->execute();  // $actionの値が自動的に使用される
}
</syntaxhighlight>
<br>
<u>セキュリティが重要な場合は、型を明示的に指定できるbindValueメソッド、または、bindParamメソッドを使用する。</u><br>
<br>
<u>※注意</u><br>
<u>ただし、実務では一貫性を保つため、特別な理由がない限りどちらか一方に統一することが推奨される。</u><br>
<br><br>
<br><br>


814行目: 1,005行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:Web]]
[[カテゴリ:Web]][[カテゴリ:MySQL]]