2017-08-16 0:09 by 仁伯爵

PHP5からPHP7へ

 このブログがgoogleのbloggerからWordPressへ移行してどれほどの時が立っただろうか。実はそのころからPHPのバージョンアップを行っていなかったので長らくこのブログを動かしているPHPはヴァージョン5.2だった。自分で管理しているサーバーではなく、間借りしているレンタルサーバーなので環境には無頓着だったのだ。VirtualBoxで同じ環境の開発環境を手元に作ったときに使われているソフトウェアバージョンを確認したが、そのあとは放置していた。任せっきりだったのだ。このブログは、さくらインターネットのさくらのレンタルサーバー・スタンダードプランを借りている。あるとき、SSLの更新作業で管理画面にログインしてついでにいろいろと管理メニューを眺めてみたら、PHPのバージョン選択にPHP7という選択肢が追加されていることに気づいた。確認してみるとこんなお知らせが出ていた。↓

  さくらのレンタルサーバ PHP7.1 提供開始のお知らせ

 バージョンが上がるたびに着々とオブジェクト指向言語としての色彩を色濃くしていくPHPだが、バージョン6をすっ飛ばしてメジャーバージョン7になったことでいろいろと性能が向上しており、一説にはWordPressをPHP5系列からPHP7系列にバージョンアップすることで約2倍の速度向上を達成した例があるという。

  WordPressが2倍に高速化。php7の威力をさくらのレンタルサーバで試してみた。(さくらのナレッジ)

戻れない楔

 さりとて互換性のない変更もいろいろと加えられているらしく、メニューからPHP7にバーンと変えただけで動くとはかぎらない。WordPressはPHP5.2からPHP7.1へバージョンアップしても難なく動いた。さすがWordpressはいろいろな環境で動くことを考慮されて作られている。えらい。しかし、我がアンテナサイト構築用WordPressテーマ AntenaInstitute(PHP5版)はうまく動かなかった。そのため、原因を究明し解決した AntenaInstitute(PHP7版)を作る必要があったのだが、その大きな原因の一つはPHP7からext/mysql 関数のすべてが廃止されてしまったことにある。ext/mysql 関数はPHP5.0 で非推奨となっておりついにPHP7で廃止されてしまった。なので、これからPHPでMySQLに接続する場合はPDOを使うか、mysqliを使うかの二択となる。

mysqliかPDOか

 では、mysqliかPDOかどっちがいいのか。公式ドキュメントにあたってみると以下のリンクにあるような感じ。

  PHP: どの API を使うか – Manual

 mysqliはMySQLの機能を余すところなく使うことができ、PDOはできないこともあるけれどドライバを入れ替えれば同じ書き方でほかのDBにも接続できるというメリットがある。とはいえPDOは異なるRDBMSで同じ書き方ができると言ってもRDBMS間で存在しない機能をエミュレートしたりはしないので、結局DB固有の機能を使おうと思うと固有の書き方が必要になったりする。PDOを使ったからと言ってMySQLでもPostgresqlでも両対応というようなプログラムが簡単に書けるかというとそうでもないような気がする。調べれば調べるほどどっちでもいいんじゃないかというような気になってしまうので、両方の使ってみた。次の節からサンプルコードを書いてみたけれどDB名やユーザー名、パスワードは以下の通り定数をdefineしているものとして読み替えていただきたい。


define('DB_HOST', データベースサーバーアドレス);
define('DB_NAME', データベース名);
define('DB_USER', データベースユーザー名);
define('DB_PASSWORD', データベースユーザーパスワード);
define('DB_CHARSET', データベースの文字コード);

 mysql関数とmysqliとPDOで、それぞれDBサーバーにコネクトして、使うデータベースを指定して、SELECT文のSQLのクエリを発行し、該当した件数を表示するサンプルでそれぞれの違いを見てみた。

今は亡きmysql関数の場合

 まずは、今までmysql関数を使った場合。mysql_connectを使ってコネクトして、mysql_select_dbを使って使用するDBをセレクトし、SQLを発行して終わったらクローズという、四段がまえの手続きになる。


//コネクトする
$link = mysql_connect( DB_HOST , DB_USER , DB_PASSWORD);
if (!$link) {
	echo $link;
	$sql_error = "mysql_error()";
	die($sql_error);

} else { 
	echo "DB connect success!<br>"; 
}

//使用DBを選択
$db_selected = mysql_select_db( DB_NAME , $link);
if (!$db_selected) {
	echo $db_selected;
	$sql_error = mysql_error();
	die($sql_error);

} else { 
	echo "DB select success!<br>"; 
}

//SELECT文を発行
$result = mysql_query('select ID,Name from member_tb where Name = "Mako Ishino"'); 
if (!$result) {
	echo 'select failed.' ;
	$sql_error = mysql_error();
	die($sql_error);
} else {
	echo "select success!<br>";
}

//ヒット数を表示
$duplicate_num = mysql_num_rows($result) ;
echo $duplicate_num ." 件該当しました。<br>\n";

//接続をクローズ
mysql_close($link) 


mysqliの場合

 続いてmysqliの場合。mysqliは関数で手続き型の書き方も、オブジェクトを使ったオブジェクト指向の書き方も両方できる。PHPの方向性として手続き型からオブジェクト指向へとシフトする動きの中でオブジェクトのほうが推奨されているので、オブジェクトを使って書いてみる。DBコネクトとセレクトがいっぺんにできるので、手順が一つ減って三段構えとなりちょっとすっきりする。それ以外はあんまり代わり映えしない手順になる。


//DBを選択してコネクト
$link = new mysqli(DB_HOST , DB_USER , DB_PASSWORD , DB_NAME);
if ($link->connect_error){
	$sql_error = $link->connect_error;
	error_log($sql_error);
	die($sql_error);
} else {
	$link->set_charset(DB_CHARSET);
	echo "connect and use success!<br>";
}

//SELECT文を発行
$result = $link->query('select ID,Name from member_tb where Name = "Mako Ishino"');
if (!$result) {
	$sql_error = $resultb->error;
	echo 'select failed.<br>' ;
	error_log($sql_error);
	die($sql_error);

} else {
	echo "select success!<br>";
}

//ヒット数を表示
$duplicate_num = $result->num_rows ;
echo $duplicate_num ." 件該当しました。<br>\n";

//接続をクローズ
$link->close();

PDOの場合

 次に、DPOの場合。前の二つでは戻り値が空かどうかで成功と失敗を区別しエラーハンドリングしていたが、PDOは例外をtryで監視し、cacheで例外発生を捕まえてエラーハンドリングを行う。接続エラーでは例外を発するが、SLQエラーの時には発生しないなどの挙動の違いがあったりなかったりしてややこしいのPDOでインスタンスを作るときに最後に渡した配列の中に”PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION”を指定してエラーは例外を発生させましょうねという指定をしておく。”PDO::ATTR_EMULATE_PREPARES => false”は、SQLインジェクション対策にプリペアドステートメントのエミュレーション機能を使わないように指定しているが、必須ではなく状況によってtrueにしたりfalseにしたりするといい。php5.2以降は指定しなければデフォルトはtrueになっている。エラーハンドリングの記述がまとめられてるのでさらにすっきりする。PDO::exec()を使うとSQL文を実行した後にそのSQLが作用した件数を戻り値で返すのだが、PDO::exec()はSELECT文には値を返さない。今回は例としてSELECT文を選んでしまったのでSQLの実行にPDO::query()を使って件数の取得にPDO::rowCount()を使っている。最後にオブジェクトをnullで上書きして接続をクローズする。


try{
	//DBを選択してコネクト
	$db_perm = array(
			PDO::ATTR_EMULATE_PREPARES => false,
			PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
		);
	$link = new PDO('mysql:host='.DB_HOST.'; dbname='.DB_NAME.'; charset='.DB_CHARSET , DB_USER, DB_PASSWORD, $db_perm);

	//SELECT文を発行
	$result = $link->query('select ID,Name from member_tb where Name = "Mako Ishino"'); 

	//ヒット数を表示
	$duplicate_num =  $result->rowCount();
	echo $duplicate_num ." 件該当しました。<br>\n";

	//接続をクローズ
	$result = null;
	$link = null;

} catch( PDOException $e) {
	$db_error = $e->getMessage();
	error_log($db_error);
	print 'DBエラー: ' . $db_error  .'<br>' ;
	die($db_error);
}

まとめ

 それぞれ使ってみた結果、PDOはとてもすっきりするけれど、mysqliのほうが実行時間が短い気がする。とくに理由が無ければmysqliを使うといいんじゃないかと思う。でもやはりPDOの書き方を覚えておくとドライバを変えればDB2でもOlacleでもSQLiteでもいろんなものに応用できるかもしれない。結局のところ、どっちでもいいんじゃないか、そんな気がした。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*


*

投げ銭はこちらへ
bitcoin :
1FtNVmXFAkwKPPz7MTcbNXzRnKJaYdMyKf

bitcoin :
1AFU37YroGt8ohmFz8nG1N2ockL56Z4hfQ

2017年11月
« 10月    
 12345
6789101112
13141516171819
20212223242526
27282930  
カテゴリー