JSONのオブジェクトは順序性を持たない
jQueryでリクエストを投げてPHPで配列のデータをJSON形式で返すアプリケーションを考える。
サーバ側のプログラムのサンプル。
$data = array('5' => array('areaName' => '大森')
, '7' => array('areaName' => '蒲田')
, '3' => array('areaName' => '大井町'));
print json_encode($data);
クライアント側のプログラムのサンプル。data はPOSTパラメータでサーバ側では使っていないが、Ajaxでサーバ側にパラメータを渡す例として書いておいた。
var url = "./ajax.php";
var data = { "mode" : "hoge" };
$.post(url, data,
function(data) {
for (var key in data) {
alert("key=" + key + ",areaName=" + data[key].areaName);
}
},
"json"
);
これを実行するとクライアント側ではサーバ側の元のデータの順序、つまり「大森」、「蒲田」、「大井町」と表示されると期待してしまうが、実際は「大井町」、「大森」、「蒲田」の順で表示される。
#Firefoxの場合。他のブラウザでは試していない。
原因はPHPの json_encode() がPHPの配列をJSONのオブジェクトに変換してしまうためである。実際のレスポンスのボディは以下のようになっている(デコードしてインデントを付けている)。
{
"5": {
"areaName": "大森"
},
"7": {
"areaName": "蒲田"
},
"3": {
"areaName": "大井町"
}
}
これは3つのプロパティを持つJSONオブジェクトであり、配列ではないのでプロパティに順序なんてない。実際の出力の順序を見るとプロパティ名の降順で出力しているように見える。たまたまかもしれないが。
対策としては、サーバ側で json_encode() を使うのをやめて、PHPの配列を受け取ってJSON形式の配列を返す処理を自前で書けばいい。
修正したコードを以下に示す。下記のサーバ側コードで json_encode() の代わりの関数 json_array_encode() は汎用的なものではなく、配列のデータの形式が決まっているものとしてその形式だけにとりあえず対応したものである。json_array_encode() ではareaNameの値をUNICODEコードポイントの文字列に変換するために json_encode() を使っている。
サーバ側
$data = array('5' => array('areaName' => '大森')
, '7' => array('areaName' => '蒲田')
, '3' => array('areaName' => '大井町'));
print json_array_encode($data);
exit;
function json_array_encode($data) {
$buf = array();
foreach ($data as $k => $v) {
$buf[] = '{"areaId":"' . $k . '","areaName":' . json_encode($v['areaName']) . '}';
}
return '[' . implode(',', $buf) . ']';
}
クライアント側
var url = "./ajax.php";
var data = { "mode" : "aaa" };
$.post(url, data,
function(data) {
for (var key in data) {
alert("areaId=" + data[key].areaId + ",areaName=" + data[key].areaName);
}
},
"json"
);
修正後のレスポンスのボディは以下のようにオブジェクトではなく配列となっている。
表示の順序は「大森」、「蒲田」、「大井町」とサーバ側のPHPの配列の順序どおりになる。
[
{
"areaId": "5",
"areaName": "大森"
},
{
"areaId": "7",
"areaName": "蒲田"
},
{
"areaId": "3",
"areaName": "大井町"
}
]
参考ページ: PHPと異なり,JavaScriptの連想配列とfor in構文には順序の概念がないので注意すること - プログラミングとIT技術をコツコツ勉強するブログ









Recent Comments