これまでは単に「SELECT 1」として動きを見ていただけでテーブル参照をしてこなかったので、MySQLに接続できてさえいればそれで動きを確認できました。
今度は具体的にデータを作成して動きを見ていきましょ
特に文字コード周りなんぞ注視していくことにします。
ではデータベース領域を作成してそこにテーブルを作りテストデータを入れてみることにします。
まず初期化スクリプトをファイルに書いて、これを流し込んでデータ作成する手順でいきます。
【メモ】
ファイル名:test.ddl
データベース領域:MYDB
テーブル名:MYTAB
いつもはシフトJIS使いなんですが、グローバルスタンダードに合わせて使い慣れないUTF-8を使ってみましょ
初期化スクリプトファイルの文字エンコーディングがUTF-8であることを確認できたら、コマンドラインから流し込みます。
マルチバイトコードを含む場合、流し込む際に「--default-character-set」オプションを使って教える必要があります。
はいこれでデータはできました。
前回作成したDBクラスを使って、このデータを文字化けさせずに読めるか試してみます。
今回から親クラスを別ファイルに分けました。
var_dumpの結果
あれれれ、、うまくいきませんでしたね。
これはPHPから接続した時に違う文字エンコーディングで認識された状態で取得してるからでしょうね。
ま、レコード数が3つであることとカラム名が合ってるようなので文字化けさえ解消できればよさそうです。
ということで次は接続後に文字エンコーディング指定してみましょ
var_dumpの結果
はい、バッチシです!!
でも一見解決したように見えて、これで少々問題勃発ですな。。
SQL発行する直前に毎回「SET NAMES utf8」も実行するのかと、
でも安心あれ
こういう毎度毎度の同じ処理は、せっかく作った親クラスに押し込めるべきでしょう!
ということで親クラスの修正をば。。
親クラス(修正版)
はいーっ、こんな感じになりました。
ではこの後どうしましょ
とりあえずこれにいろいろいちゃもん付けてみましょ
うーん、セクシーさが足りないよね。
あと、まだINSERTやらUPDATE,DELETEとかって試してないよね。
となるとprepare()してexecute()しないといけないし面倒じゃないかい?
そうそう、レコードを大量に更新する場合にプリペアドステートメント使って連続バインドを簡単にできるのか?
あとエラー発生したらログ保存したりしてデバッグを楽にできないと使い物にならないよね。
そうだ肝心なこと忘れてた、接続設定を一箇所に共通でしておきたいけど、毎度の処理で必ずデータベース必要とするとは限らないよね。
そういう場合は必要なときだけ接続するようにしたいよね。接続の負荷とか考えるとね。
人間はわがままです。
今度は具体的にデータを作成して動きを見ていきましょ
特に文字コード周りなんぞ注視していくことにします。
ではデータベース領域を作成してそこにテーブルを作りテストデータを入れてみることにします。
まず初期化スクリプトをファイルに書いて、これを流し込んでデータ作成する手順でいきます。
-- test.ddl
CREATE DATABASE IF NOT EXISTS MYDB;
use MYDB;
CREATE TABLE MYTAB(
ID INT,
NAME VARCHAR(10)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO MYTAB VALUES(1, '富士');
INSERT INTO MYTAB VALUES(2, '鷹');
INSERT INTO MYTAB VALUES(3, 'なすび');
CREATE DATABASE IF NOT EXISTS MYDB;
use MYDB;
CREATE TABLE MYTAB(
ID INT,
NAME VARCHAR(10)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO MYTAB VALUES(1, '富士');
INSERT INTO MYTAB VALUES(2, '鷹');
INSERT INTO MYTAB VALUES(3, 'なすび');
【メモ】
ファイル名:test.ddl
データベース領域:MYDB
テーブル名:MYTAB
いつもはシフトJIS使いなんですが、グローバルスタンダードに合わせて使い慣れないUTF-8を使ってみましょ
初期化スクリプトファイルの文字エンコーディングがUTF-8であることを確認できたら、コマンドラインから流し込みます。
マルチバイトコードを含む場合、流し込む際に「--default-character-set」オプションを使って教える必要があります。
# mysql -uroot --default-character-set=utf8 </path/to/test.ddl
はいこれでデータはできました。
前回作成したDBクラスを使って、このデータを文字化けさせずに読めるか試してみます。
<?php
// 前回作成した親クラス呼び出し
require '/path/to/DB.inc';
$db = new DB("", "MYDB");
$db->query("SELECT * FROM MYTAB");
$rows = $db->fetchAll(); // 全レコード取得
// UTF-8で取得したものをシフトJISで表示させる変換
mb_convert_variables("SJIS-win", "UTF-8", $rows);
var_dump($rows);
// 前回作成した親クラス呼び出し
require '/path/to/DB.inc';
$db = new DB("", "MYDB");
$db->query("SELECT * FROM MYTAB");
$rows = $db->fetchAll(); // 全レコード取得
// UTF-8で取得したものをシフトJISで表示させる変換
mb_convert_variables("SJIS-win", "UTF-8", $rows);
var_dump($rows);
今回から親クラスを別ファイルに分けました。
var_dumpの結果
array(3) {
[0]=>
array(2) {
["ID"]=>
string(1) "1"
["NAME"]=>
string(2) "??"
}
[1]=>
array(2) {
["ID"]=>
string(1) "2"
["NAME"]=>
string(1) "?"
}
[2]=>
array(2) {
["ID"]=>
string(1) "3"
["NAME"]=>
string(3) "???"
}
}
[0]=>
array(2) {
["ID"]=>
string(1) "1"
["NAME"]=>
string(2) "??"
}
[1]=>
array(2) {
["ID"]=>
string(1) "2"
["NAME"]=>
string(1) "?"
}
[2]=>
array(2) {
["ID"]=>
string(1) "3"
["NAME"]=>
string(3) "???"
}
}
あれれれ、、うまくいきませんでしたね。
これはPHPから接続した時に違う文字エンコーディングで認識された状態で取得してるからでしょうね。
ま、レコード数が3つであることとカラム名が合ってるようなので文字化けさえ解消できればよさそうです。
ということで次は接続後に文字エンコーディング指定してみましょ
<?php
// 親クラス呼び出し
require '/path/to/DB.inc';
$db = new DB("", "MYDB");
$db->query("SET NAMES utf8"); <-追加
$db->query("SELECT * FROM MYTAB");
$rows = $db->fetchAll(); // 全レコード取得
// UTF-8で取得したものをシフトJISで表示させる変換
mb_convert_variables("SJIS-win", "UTF-8", $rows);
var_dump($rows);
// 親クラス呼び出し
require '/path/to/DB.inc';
$db = new DB("", "MYDB");
$db->query("SET NAMES utf8"); <-追加
$db->query("SELECT * FROM MYTAB");
$rows = $db->fetchAll(); // 全レコード取得
// UTF-8で取得したものをシフトJISで表示させる変換
mb_convert_variables("SJIS-win", "UTF-8", $rows);
var_dump($rows);
var_dumpの結果
array(3) {
[0]=>
array(2) {
["ID"]=>
string(1) "1"
["NAME"]=>
string(4) "富士"
}
[1]=>
array(2) {
["ID"]=>
string(1) "2"
["NAME"]=>
string(2) "鷹"
}
[2]=>
array(2) {
["ID"]=>
string(1) "3"
["NAME"]=>
string(6) "なすび"
}
}
[0]=>
array(2) {
["ID"]=>
string(1) "1"
["NAME"]=>
string(4) "富士"
}
[1]=>
array(2) {
["ID"]=>
string(1) "2"
["NAME"]=>
string(2) "鷹"
}
[2]=>
array(2) {
["ID"]=>
string(1) "3"
["NAME"]=>
string(6) "なすび"
}
}
はい、バッチシです!!
でも一見解決したように見えて、これで少々問題勃発ですな。。
SQL発行する直前に毎回「SET NAMES utf8」も実行するのかと、
でも安心あれ
こういう毎度毎度の同じ処理は、せっかく作った親クラスに押し込めるべきでしょう!
ということで親クラスの修正をば。。
親クラス(修正版)
<?php
/**
* @filename DB.inc
*/
class DB extends PDO
{
protected $_sth = null;
public function __construct($host='', $dbname='') {
list($host, $dbname, $user, $pass) = $this->_set_info($host, $dbname);
try {
parent::__construct("mysql:dbname={$dbname};host={$host}", $user, $pass);
parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
parent::setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$this->query("set names utf8"); <-追加
} catch (PDOException $e) {
die($e);
}
}
protected function _set_info($host, $dbname) {
if (empty($host)) $host = 'localhost';
if (empty($dbname)) $dbname = 'mysql';
return array($host, $dbname, 'root', '');
}
public function query($sql) {
$this->_sth = parent::query($sql);
return $this->_sth;
}
/* 継承メソッドと同じなので不要
public function exec($sql) {
return parent::exec($sql);
}
*/
public function prepare($sql) {
$this->_sth = parent::prepare($sql);
return $this->_sth;
}
public function execute($param=array()) {
$this->_sth->execute($param);
return $this->rowCount();
}
public function rowCount() {
return $this->_sth->rowCount();
}
public function fetch() {
return $this->_sth->fetch();
}
public function fetchAll() {
return $this->_sth->fetchAll();
}
}
/**
* @filename DB.inc
*/
class DB extends PDO
{
protected $_sth = null;
public function __construct($host='', $dbname='') {
list($host, $dbname, $user, $pass) = $this->_set_info($host, $dbname);
try {
parent::__construct("mysql:dbname={$dbname};host={$host}", $user, $pass);
parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
parent::setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$this->query("set names utf8"); <-追加
} catch (PDOException $e) {
die($e);
}
}
protected function _set_info($host, $dbname) {
if (empty($host)) $host = 'localhost';
if (empty($dbname)) $dbname = 'mysql';
return array($host, $dbname, 'root', '');
}
public function query($sql) {
$this->_sth = parent::query($sql);
return $this->_sth;
}
/* 継承メソッドと同じなので不要
public function exec($sql) {
return parent::exec($sql);
}
*/
public function prepare($sql) {
$this->_sth = parent::prepare($sql);
return $this->_sth;
}
public function execute($param=array()) {
$this->_sth->execute($param);
return $this->rowCount();
}
public function rowCount() {
return $this->_sth->rowCount();
}
public function fetch() {
return $this->_sth->fetch();
}
public function fetchAll() {
return $this->_sth->fetchAll();
}
}
はいーっ、こんな感じになりました。
ではこの後どうしましょ
とりあえずこれにいろいろいちゃもん付けてみましょ
うーん、セクシーさが足りないよね。
あと、まだINSERTやらUPDATE,DELETEとかって試してないよね。
となるとprepare()してexecute()しないといけないし面倒じゃないかい?
そうそう、レコードを大量に更新する場合にプリペアドステートメント使って連続バインドを簡単にできるのか?
あとエラー発生したらログ保存したりしてデバッグを楽にできないと使い物にならないよね。
そうだ肝心なこと忘れてた、接続設定を一箇所に共通でしておきたいけど、毎度の処理で必ずデータベース必要とするとは限らないよね。
そういう場合は必要なときだけ接続するようにしたいよね。接続の負荷とか考えるとね。
人間はわがままです。