PHP PDOで数値キーを含まない連想配列を返すには

2018-08-23

Web開発

PHPでデータベースからデータを取得する際には、PDOを用います。
このPDOでSELECTしてfetchAll()で結果を取ってくると、次のような配列と連想配列がごちゃ混ぜになった連想配列が取得できます。

[
  {
    "0": "value",
    "column": "value"
  }
]

どんな時に影響が出るか

例えば、ユーザー投稿型のWebサービスのREST APIをPHPで作っているとします。
全ての投稿を取得するAPIにGETリクエストをすると、JSONで全ての投稿が返ってくるAPIを作らなければなりません。

こうしたときに、先ほどのような数値キー(numeric key)を含んでいると、データ量が想定していた大きさのほぼ二倍になってしまいます
多くのデータが通信され、通信帯域を圧迫する原因になり得ます。

対処法

PDOにはFetchModeという、fetch()、fetchAll()で返すデータのフォーマットを指定できる機能があります。
デフォルトで設定されているモードはFETCH_BOTHで、カラム順の数値キーとカラム名の文字列キーのそれぞれをキーとした連想配列を返します。
そのため、先ほどのような結果が帰ってきていました。

今回は、数値キーを消したいので、FETCH_ASSOCを指定します。これはカラム名の文字列キーのみをキーとした連想配列の配列を返すモードです。ASSOCはAssociative Array(連想配列)の略です。
以下のような手順でfetchAll()します。

$prepare = $database->prepare("SELECT * FROM `table`");
$prepare->execute();
$ret = $prepare->fetchAll(PDO::FETCH_ASSOC);

こうすることで、$retに次のような配列が入ります。

[
  {
    "column": "value"
  },
  {
    "column": "value"
  }
]

配列ではなく、先頭カラムをキーとした連想配列で取得する

それぞれのレコードに一意なIDが割り振られているテーブルから取得するとき、ソート順の配列ではなくIDで取得したい場合があります。
そのためには、FETCH_ASSOCFETCH_UNIQUEを指定します。

以下のように、OR演算して指定します。

$prepare = $database->prepare("SELECT * FROM `table` WHERE `gender` = 'male'");
$prepare->execute();
$ret = $prepare->fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_UNIQUE);

結果は以下のようになります。

{
  "2": {
    "id": 2,
    "column": "value"
  },
  "5": {
    "id": 5,
    "column": "value"
  }
}

このモードは非常に便利で、様々な状況下で使うことができます。とくに、IDが連番ではない場合と、WHERE句などでIDが飛び飛びになっている場合などで有用です。