LoginSignup
12
9

More than 5 years have passed since last update.

PHPの配列を安全にJSONシリアライズする

Last updated at Posted at 2014-11-13

以前 PHPのlist()はタプル展開のための機能 - Qiita にも書きましたが、PHPの配列型は非常に多くの機能はあり、0から始まる連番のインデックスを持つ「配列」としての側面と、ほかの言語で連想リスト(Association list, alist)やハッシュマップ、辞書などと呼ばれるコレクションとしての側面を合せ持ちます。

この仕様はとてもいいところと悪いところがあるのですが、PHPの型をPHP以外に出力(シリアライズ)するときには若干困ることがあります。たとへば、PHPの配列をjson_encodeでJSONにシリアライズするときなどです。

問題

<?php

$num = range(1, 10);
echo json_encode($num).PHP_EOL;
// => [1,2,3,4,5,6,7,8,9,10]
// これは想定通り

$num = range(1, 10);
// 奇数ならtrueを返す函数
$is_odd = function ($n) { return $n % 2 === 1; };
$num = array_filter($num, $is_odd);
echo json_encode($num).PHP_EOL;
// => {"0":1,"2":3,"4":5,"6":7,"8":9}
// あれれー

解決策

array_valuesです… 配列にarray_valuesを掛けると、純粋な配列であることを保証できるようになります… かつ、最初から連番の配列にarray_valuesを使っても安全です…

逆に、数値で連番であるがJSONにはオブジェクト型にしてやりたい、といふときはjson_encodeJSON_FORCE_OBJECTフラグを立ててやるといいです。

<?php
/**
 * @param  array  $value
 * @param  int    $options
 * @param  int    $depth
 * @return string JSON
 * @link   http://php.net/manual/function.json-encode.php
 */
function json_encode_array(array $value$options = 0, $depth = 512)
{
    return json_encode(array_values($value, $options, $depth));
}

/**
 * @param  array|object $value
 * @param  int    $options
 * @param  int    $depth
 * @return string JSON
 * @link   http://php.net/manual/function.json-encode.php
 */
function json_encode_object($value, $options = 0, $depth = 512)
{
    $options |= JSON_FORCE_OBJECT;

    return json_encode($value, $options, $depth);
}

これでハッピーになれますね!

おまけ

JSONを利用してるみなさまには釈迦に説法なのですが、JSONの仕様によれば「ほかの言語で連想リスト(Association list, alist)やハッシュマップ、辞書などと呼ばれるコレクション」に相当する、 {"key": "value"} のようなものの名前(型)は「object」です。

ってことは、json_decodeに第二引数を渡さなかったときに、デフォルトでstdClassになるのも自然… ってそんなわけあるかstdClassはちょっとつらい。

幸ひにしてPHPの配列とstdClassはキャストで簡単に相互変換できるからいいんですけどね、いいんですけどね。

あとがき

PHP - 文字列配列から空文字を除去するバッドノウハウ - Qiita にも似たようなこと書いてた。


補足

すっかり忘れてたんだけどJSON_FORCE_OBJECTフラグを立てると、要素も再帰的にオブジェクトになるので、場合によってはコレジャナイ結果を引き起すことがあるかも。ってわけで今回紹介したjson_encode_objectが役に立つことって少ないんじゃないですかね。

12
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
9