デバッグを出力してると逆に確認できないこともある

この記事はだいぶ前に書かれたものなので情報が古いかもしれません

さりげにTwitterでもこの前こそっとつぶやいてましたが、どうしても原因の分からないエラーが発生して、いろいろと調べているうちに、不意に解決方法が閃いた、今日はそんなお話です。


jQueryでAjax通信を行う際に、$.ajaxって関数を使うことがあるかと思います。

こんな風に。

$.ajax({
    type: "POST",
    data: $(form).serialize(),
    url: 'test.php'
    success: function(data) {
        alert(data);
    }
});

この関数の詳細な説明などはリファレンスにお任せするとして、まあこんな感じで非同期通信を行うわけですね。画面遷移などをすることなく、Ajaxで通信を行ってDBにアクセスしたりするときなんかに使うと思います。

で、ですね。例えばphp側にデータを渡して、何やらごちゃごちゃと処理した後に、またphpからデータを渡すような処理があるとするじゃないですか。

上記の例だと、test.phpにフォームのデータを送信していますので、まあ、じゃあphpでそのデータを意味もなくまたjavascript側に渡すような処理を書いてみましょうか。ただ上の例だと$(form).serialize()って何ぞって話になったりするとめんどいので、ここはちょっと書き換えましょう。


まずは単純にデータの内容を出力してみる


//javascript側
$.ajax({
    type: "POST",
    data: 'id=1&name=test',
    url: 'test.php'
    success: function(data) {
        alert(data);
    }
});

//php側(test.php)
print_r($_POST);

相も変わらずものすごい端折った感じですが、こんな処理を書くとですね、無事にAjax通信が行われた場合、以下のような内容がアラートダイアログに出ます。

Array(
    [id]=>1
    [name]=>test
)

要はPOSTされたデータがそのまま出力されるわけですね。$.ajaxの中で『success:function(data){}』ってのがありますが、このdataの部分、関数の第一引数にはサーバーからの戻り値……で良いのかな? それが入ってきます。なので、今回の場合でいえば、test.phpの中で出力している内容がそのままdataという変数で受け取れるってことですね。それをアラートしているので、$_POSTの内容がダイアログの中に出ると、乱暴に説明するとそんな流れです。


JSON形式のデータを出力してみる

さて、こうして無事にPOSTした内容が出力されたのは良いんですが、じゃあこの出力された配列をそのままjavascript側で使えるのかというと、実は使えません。

$.ajax({
    type: "POST",
    data: 'id=1&name=test',
    url: 'test.php'
    success: function(data) {
        alert(data['id']);
        alert(data['name']);
    }
});

こんな風に書いてもですね、アラート画面の中には「undifined」の文字が虚しく出力されるだけです。

では、そういう場合はどうすればいいのか。

いくつか方法はあるのかもしれないですが、php側でJSON形式にデータを変換して出力させるというやり方があります。

これも細かい説明については省きますけど、上記のデータをJSON形式にすると、こんな感じになります。

{'id':'1','name':'test'}

なので、test.phpでこれを出力する。

//javascript
$.ajax({
    type: "POST",
    data: 'id=1&name=test',
    url: 'test.php'
    success: function(data) {
        alert(data['id']);
        alert(data['name']);
    }
});

//php
echo "{'id':'".$_POST['id']."','name':'".$_POST['name']."'}";

こうすると、無事に配列の値がダイアログの中に出てくる……


はずなんですけど。


はずなんですけど、このままだとなぜか上手くいかないんですよね。実はその辺りの原因を詳しく調べてないので分からないのですが、解決方法だけ書くと、こうなります。

//javascript
$.ajax({
    type: "POST",
    data: 'id=1&name=test',
    url: 'test.php'
    success: function(data) {
        obj = eval("("+data+)")";
        alert(obj['id']);
        alert(obj['name']);
    }
});

//php
echo "{'id':'".$_POST['id']."','name':'".$_POST['name']."'}";

何か一回evalを噛ませてやるといいみたいです。これ何でだったっけな……ちょっと忘れちゃいました。さーせん。

とにかく、これで無事に配列の値がダイアログの中に出てくる……


はずなんですけど!


はずなんですけど、なぜかエラーになる場合があるんですよねぇ。

まったくもう……。


デバッグの罠(CakePHPで開発している場合)

さあ、実は今日の本題はここからです。前置きが長くなっちゃいましたけど、でもこの前置きがあった上での本題なので、勘弁してつかあさい。

上記のような感じで、配列の中身を各個に使おうとしたところまでは良かったんですが、何度やってもこんな↓エラーが出て参っちゃったんですよ、ほんまに。


missing ) in parenthetical


カッコが足りないよ? 的なエラーかな……? これがなぜか『obj = eval(“(“+data+)”);』のところの処理で出てた。

もうこれ以上長ったらしい説明を書いてもあれなんで、ざっくり結論だけ書きますけど、デバッグを出力していたのが原因でした。

CakePHPを使ってローカル環境で開発しているときって、たぶんデバッグを出力させていることが多いと思うんですよね。

これまた上記の例でいきますと、デバッグをONにしている状態でtest.phpみたいな処理を書いて出力させようとすると、アラートの中身がこんな感じになるんですよ。

//javascript
$.ajax({
    type: "POST",
    data: 'id=1&name=test',
    url: 'test.php'
    success: function(data) {
        alert(data);
    }
});

//php
echo "{'id':'".$_POST['id']."','name':'".$_POST['name']."'}";

//アラートダイアログの中身
{'id':'1','name':'test'}

何かJSON形式で書いた文字列の後ろに変なの出てますよね。こいつが曲者だったようです。javascriptは別にデバッグが出力されている部分を「こいつはデバッグ結果だから取り除いておいてやろう」みたいな親切心は持ち合わせていないので、単純にechoした内容を一つの文字列として扱ってしまいます。

だから要するにこれ、JSON形式として不正なものになっちゃってるわけですね。javascriptさんが「何か余計な文字が混じってやがるぜ、ふざけるな」って怒ってるわけですね。それが上記のエラーにつながったと、そういうわけですね。まあ、それで何でカッコが足りないぜ的なエラーになるのかはよく分かりませんが。

いずれにしても、デバッグを出さないようにして処理を実行したら、無事に配列の中身がダイアログに出てくるようになりました。

今回はほんとに大丈夫です。三度目の正直です。仏の顔だって三度までだからな。これで「はずなんですけどぉぉ」とか言ってしまった日にゃ、焼き土下座もんだぜい。


因果は繰り返す

冒頭で、解決方法が不意に閃いたとか言いましたが、どうして不意に閃いたのかというと、実は数ヶ月前に、全く同じ状況で足止めを食ったことがあったんですよ。だから正確には閃いたんじゃなくて、思い出しただけですねww

前にもAjaxで似たような処理を書いていて、やっぱりあのmissing~ってエラーがどうしても消せなかったんですけど、そのときも不意に解決方法が閃いたんですよね。あ、デバッグが出力されているせいだ! ってね。

で、そのときは何で不意に解決方法が閃いたのかというと、実はそのさらに数ヶ月前に、やっぱり全く同じ状況で足止めを食ったことがあったんですよね。だから正確には閃いたんじゃなくて、思い出しただけですね(しつこい)

そのときもやっぱりAjaxで似たような処理を書いていて、やっぱりあのmissing~ってエラーどうしてもk(以下略)


ま、つまり何が言いたいのかと言うとですね……

俺って学習しねーやろーだなーってこってす。


だから、またいつの日か同じ状況に出くわしたときには余計な足止めを食ったりしないように、今回はちゃんと記録を残しておこうというわけです。

すでに同じ失敗を二度繰り返してますからね。三度目はあってはならないのです。

仏の顔も三度までですからね。

まだコメントはいただけてないみたい……
もしかしたら何か関連しているかも?