[PHP] mysqli使い方まとめ（MySQL接続～SELECT実行まで）

PHP5.5から `mysql_connect()` や `mysql_query()` など、`mysql_***`系の関数は非推奨となりました。新方式の１つである **mysqli** の使い方をまとめておきます。（他にはPDO方式があります）

# ![](//goo.gl/tuSQrq) 手続き型とオブジェクト型

**mysqli** の書き方には大きく２通りあります。
　**◎手続き型**：従来とよく似た `mysqli_***()` という書き方（インスタンス生成不要）
　**◎オブジェクト型**：オブジェクト指向的な書き方（インスタンス生成必要）

例）DBへの接続

```php:手続き型
// DB接続例：mysqli_xxx関数を使う
$link = mysqli_connect("Host or IP", "User", "Pass", "DBName");
```

```php:オブジェクト型
// DB接続例：mysqliクラスをオブジェクト化してから使う
$mysqli = new mysqli('Host or IP', 'User', 'Pass', 'DBName');
```

本ページでは、主に後者の**オブジェクト型**の書き方について記載します。

# ![](//goo.gl/tuSQrq) DBへの接続〜切断

```php:PHP
<?php
// mysqliクラスのオブジェクトを作成
$mysqli = new mysqli('Host or IP', 'User', 'Pass', 'DBName');
if ($mysqli->connect_error) {
    echo $mysqli->connect_error;
    exit();
} else {
    $mysqli->set_charset("utf8");
}

// ここにDB処理いろいろ書く（後述）

// DB接続を閉じる
$mysqli->close();
?>
```

# ![](//goo.gl/tuSQrq) SELECT（簡易方式）

完成しているSQLをqueryメソッドでそのまま実行する方式です。

```php:PHP
// 完成済みのSELECT文を実行する
$sql = "SELECT user_id, name FROM user_table";
if ($result = $mysqli->query($sql)) {
    // 連想配列を取得
    while ($row = $result->fetch_assoc()) {
        echo $row["user_id"] . $row["name"] . "<br>";
    }
    // 結果セットを閉じる
    $result->close();
}
```

#### SELECT件数の取得：

```php:PHP
// オブジェクト型
echo "rows=" . $result->num_rows;

// 手続き型
echo "rows=" . mysqli_num_rows($result);
```


# ![](//goo.gl/tuSQrq) SELECT（バインド方式）

SQLの一部を「?」としておき、あとから変数の値で補う（バインドする）方式です。

```php:PHP
// SELECT文のひな型をもとにステートメントハンドルを取得する
$sql = "SELECT user_id, name FROM user_table WHERE user_id=? AND name=?";
if ($stmt = $mysqli->prepare($sql)) {
    // 条件値をSQLにバインドする（補足参照）
    $user_id = 123;
    $name = "hanako";
    $stmt->bind_param("is", $user_id, $name);

    // 実行
    $stmt->execute();

    // 取得結果を変数にバインドする
    $stmt->bind_result($user_id, $name);
    while ($stmt->fetch()) {
        echo "ID=$user_id, NAME=$name<br>"; 
    }
    $stmt->close();
}
```

#### SELECT件数の取得：

```php:PHP
$stmt->store_result(); // これ忘れるとnum_rowsは0
echo "rows=" . $stmt->num_rows;
```

#### バインド式の補足：

`$stmt->bind_param("is", $user_id, $name);`の第１引数 `"is"` は後続のデータ型を表します。`i=integer、s=string、d=double、b=blob` など。DATE型は `s` で良いみたいです。
また下記のように<font color="red">値を引数内に直書きすることはできません。</font>
誤）$stmt->bind_param("is", <font color="red">123, "hanako"</font>);

# ![](//goo.gl/tuSQrq) 応用例

使いやすいようにクラス化してみる。（DB接続情報は適宜変更して下さい）

```php:MyDB.class.php
<?php
/*
 * MyDBクラス
 */
class MyDB
{
	public $mysqli; // mysqliオブジェクト
	public $mode;   // 戻り値の形式："json" or "array"（連想配列）
	public $count;  // SQLによって取得した行数 or 影響した行数
	
	// コンストラクタ
	function __construct($mode = "json") 
	{
		$this->mode = $mode;
		
		// DB接続
		$this->mysqli = new mysqli('localhost', 'DB-USER', 'DB-PASS', 'DB-NAME');
		if ($this->mysqli->connect_error) {
			echo $this->mysqli->connect_error;
			exit;
		} else {
			$this->mysqli->set_charset("utf8");
		}
	}
	
	// デストラクタ
	function __destruct()
	{
		// DB接続を閉じる
		$this->mysqli->close();
	}

	// SQL実行（SELECT/INSERT/UPDATE/DELETE に対応）
	function query($sql)
	{
		// SQL実行
		$result = $this->mysqli->query($sql);
		// エラー
		if ($result === FALSE) {
			// エラー内容
			$error = $this->mysqli->errno.": ".$this->mysqli->error;
			// 戻り値
			$rtn = array(
				'status' => FALSE,
				'count'  => 0,
				'result' => "",
				'error'  => $error
			);
			if($this->mode == "array")
				return $rtn;
			else
				return json_encode($rtn); // JSON形式で返す（デフォルト）
		}
		
		// SELECT文以外
		if($result === TRUE) {
			// 影響のあった行数を格納
			$this->count = $this->mysqli->affected_rows;
			// 戻り値
			$rtn = array(
				'status' => TRUE,
				'count'  => $this->count,
				'result' => "",
				'error'  => ""
			);
			if($this->mode == "array")
				return $rtn;
			else
				return json_encode($rtn); // JSON形式で返す（デフォルト）
		} 
		// SELECT文
		else {
			// SELECTした行数を格納
			$this->count = $result->num_rows;
			// 連想配列に格納
			$data = array();
			while ($row = $result->fetch_assoc()) {
				$data[] = $row;
			}
			// 結果セットを閉じる
			$result->close();
			// 戻り値
			$rtn = array(
				'status' => TRUE,
				'count'  => $this->count,
				'result' => $data,
				'error'  => ""
			);
			if($this->mode == "array")
				return $rtn;
			else
				return json_encode($rtn); // JSON形式で返す（デフォルト）
		}
	}

	// 文字列をエスケープする
	function escape($str)
	{
		return $this->mysqli->real_escape_string($str);
	}
}
?>
```

#### 使い方

```php:php
$db = new MyDB();
echo $db->query("SELECT * FROM USERTABLE");
```

#### 結果（JSON形式の文字列）

```json:json
{
	"status": true,
	"count" : 2,
	"result": [
		{"UserID":"aaa", "Name":"AppleMan"},
		{"UserID":"bbb", "Name":"BananaMan"}
	],
	"error" : ""
}
```

#### 補足

JSON形式の文字列に変換する `json_encode($ary)` は、通常だと日本語が `\uXXXX` 形式（Unicodeエスケープシーケンス）になってしまいます。PHP5.4以降では、
`json_encode($ary, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)`
とすることで、日本語のまま扱えます。

(･o･ゞ いじょー。

# ![](//goo.gl/tuSQrq) 参考URL

mysqli_result::fetch_assoc: 結果の行を連想配列で取得する
http://www.phppro.jp/phpmanual/php/mysqli-result.fetch-assoc.html

mysqli - プリペアドステートメント
http://blog.livedoor.jp/nakamura_tech/archives/51311243.html

【PHP】mysqliとプリペアドステートメントについて｜Furudateのブログ
http://furudate.hatenablog.com/entry/2013/10/04/211422

PHPでデータベースに接続するときのまとめ
http://qiita.com/mpyw/items/b00b72c5c95aac573b71

MySQL 改良版拡張モジュール｜PHP: MySQLi - Manual
http://php.net/manual/ja/book.mysqli.php