質問: $mouths[$i]; } //表示されない var_dump($mouths[0]); return $results; } ?> ``` こちらのPHPから呼び出します。 ``` ``` これが表示結果となります。 ``` string(6) "sample" string(6) "sample" string(6) "sample" string(6) "sample" string(6) "sample" NULL array(5) { [0]=> NULL [1]=> NULL [2]=> NULL [3]=> NULL [4]=> NULL } ``` getMouthsでvar_dump()をすると変す$i,$currentpage,$itemperpageにはきちんと値が入っていました。 なぜNULLになるのでしょうか。
回答: 質問者さんの過去質問を見ましたが、毎度されている**デバッグ依頼**ですね。 本来**非推奨な質問の域**ですが、今回だけ答えてみます。 今後同様の質問がしなくてもいいようになれば幸いですね(ニッコリ 結論から ==== 変数のスコープをきちんと理解されていないことから「なぜNULLになるのでしょうか」という質問になっています。 プログラムは指示したとおりにしか動きません。自分が思ったとおりに動くと思っていませんか? その考えは今すぐ捨てましょう。 この内容で「なぜNULLになるのか」という質問が出る時点で質問者さんは思ったとおりコードを動かせる域には到底達していません。 ミニマムコード ======= 質問者さんのやろうとしていることは下記と同等です。 ``` $a = [ ["id"=>1, "name"=>"test" ], ["id"=>2, "name"=>"test2" ], ]; function get($num){ $data = $a[$num]; return $data; } var_dump(get(1)); ``` require_once()しているから状況が違う、 と思われたのであればマニュアルをきちんと読み直してください。 同等であるためinlucde_once()の方に説明がありますが、 `include_once 命令は、スクリプトの実行時に指定 したファイルを読み込み評価します` これはPHPの場合、実行時にそこを通ったらそのプログラムを実行することを意味します。 つまり、コードが書いてあるのと同義です。 さて、本題のミニマムコードに戻りますが。 「デバッグ依頼である」と私が結論づけるのも無理がなく、上記、質問者さんのコードと同等のコードを実行するとエラーになります。 ``` PHP Notice: Undefined variable: a in XXX.php on line 13 ``` 質問者さんのほうでも同じコードを実行してみてください。 もし上記Noticeが出ていないのでしたら、エラー表示がOnになっていません。 学習段階であったり本番リリース前であったり、不完全なコードの状態では何が起きるか分かりません。 必ずエラー表示をOnにしてください。 * PHPのエラー表示設定について ※もしかしたら既に過去に指摘を受けているかもしれませんね。でもそれだけ大事です。 PHPマニュアル確認 ========== で、ここで私が「結論」にリンクを貼った変数のスコープの項を見てみてください。 序盤に下記のようなコードがありますね。 ``` $a = 1; /* グローバルスコープ */ function test() { echo $a; /* ローカルスコープ変数の参照 */ } test(); ``` このコード、私のミニマムコードとよく似ていると思いませんか? それはつまり、質問者さんのコードと同等であることを示します。 ちなみにこのコードも同じNoticeを出力します。 `Undefined variable: a` 「未定義の変数:a」 エラーの調べかたとか読み方「質問前にすること」は下記が参考になりますよ。 * エラーメッセージの読み方と対処, 検索や質問の原則 **「読んで理解して自身で実践できるようになるまで質問しない」くらいの気持ちで読んでください** つまり、変数が未定義であることを指します。 なぜかって、それはコメントに書いてある通りで、 **PHPにおいて、関数は自身の中で定義された変数しか参照できないから** です。 それがコメントで書いてある「ローカルスコープ変数の参照」の意味です。 JavaScriptと同じ感覚ではいけません。PHPの仕様です。覚えましょう。 > > PHPマニュアルより抜粋 > > このスクリプトは、出力を全く行いません。これは、echo 命令がローカ ル版の $a 変数を参照しているにもかかわらず、このスコープでは値が代入されていないからです。~中略~PHP では、グローバル変数は、関数の内部で使用する場合、関数の内部でグローバルとして宣言する必要があります。 > > > まず一歩目 ===== 変数のスコープにあるようにglobalキーワードを使うとひとまずエラーが解消できます。 ``` $a = [ ["id"=>1, "name"=>"test" ], ["id"=>2, "name"=>"test2" ], ]; function get($num){ global $a; $data = $a[$num]; return $data; } var_dump(get(1)); ``` 出力結果 ``` array(2) { ["id"]=> int(2) ["name"]=> string(5) "test2" } ``` 2歩目 === でもこれって意味がありません。 globalキーワードを使う是非はひとまず置いといて、 変数$aってどこも使ってませんよね。このget()関数のためだけに使うのは意味がないです。 引数に渡すのがその次。 ``` $a = [ ["id"=>1, "name"=>"test" ], ["id"=>2, "name"=>"test2" ], ]; function get($num,$a){ $data = $a[$num]; return $data; } var_dump(get(1,$a)); ``` でも、わざわざ定義した変数を引数で渡すって変な感じですよね。 それならこの方がいい。 ``` function get($num){ $a = [ ["id"=>1, "name"=>"test" ], ["id"=>2, "name"=>"test2" ], ]; $data = $a[$num]; return $data; } var_dump(get(1)); ``` 関数の中に定義してしまおうってことですね。 結局、変数$aはget()以外で直接どこからも参照されることがないのでしたら、これで充分です。 「データとしてしっかり持ちたいんだ」ということでしたら、 その変数$aをコード内に直接変数で持つのではなくデータベースで取得するか、クラスにしましょう。 ``` class a{ private $a = [ ["id"=>1, "name"=>"test" ], ["id"=>2, "name"=>"test2" ], ]; function getByNum($num){ return $this->a[$num]; } } $obj_a = new a(); var_dump($obj_a->getByNum(1)); ``` privateなので$obj_a->a;のようには参照できません。 * プロパティのアクセス権 もう一歩 ==== クラスのメンバーでも関数でもなんでも同じですが、メソッドって**引数に何が入ってくるか知りません**。 「プログラム組んでるんだから制御できるだろ」って思ったら大間違いです。 関数で準備した以上は、誰から実行されるかなんてわからないわけです。 複数人で同じプロジェクトで開発していたら、同じように使えるわけですし、引数って言っても変数です。変数は何が入っているか分からないもので、後から書き換え可能です。 実際のプログラムでは入力値が入ってきたりクエリストリングから受け取ったパラメータが入ってきたりして、本当に何が来るか分からないわけです。 下記のようにして引数の型を制限します。 ※とりあえず「それならこれでいい」のコードで ``` function get(int $num){ $a = [ ["id"=>1, "name"=>"test" ], ["id"=>2, "name"=>"test2" ], ]; $data = $a[$num]; return $data; } ``` これでget("a")とか、int(整数型)以外を与えるとエラーが出るようになりました。 でも、これでも不十分です。 確実に存在する値が引数として与えられるか保証はありませんよね。 この場合、2とか与えられたら下記のようなエラーが出ます。 `PHP Notice: Undefined offset: 2 in XXX.php on line 11` 未定義のオフセット:2 つまり、配列に存在しないポイント、という意味ですね。 ※配列にキーが存在しない場合と同等です 阻止するために、「存在するキーが与えられていたら取得」としましょう。 ``` function get(int $num):array{ $a = [ ["id"=>1, "name"=>"test" ], ["id"=>2, "name"=>"test2" ], ]; if(array_key_exists($num,$a)){ return $a[$num]; } return []; } ``` ついでに、返り値の型も宣言しておき、存在した場合、そのまま返却、そうでない場合は空の配列を返すようにしました。 これでひとまずいい感じにはできましたね。 あとは自身のコードに考え方を反映するだけ! 頑張ってください。 ちなみに短く書くならこう。 ``` function get(int $num):array{ $a = [ ["id"=>1, "name"=>"test" ], ["id"=>2, "name"=>"test2" ], ]; return (array_key_exists($num,$a))?$a[$num]:[]; } ``` デバッグについて ======== そういえば、各所でvar_dump()を入れられてデバッグをされていますが、本来確認しなければならない項目を確認していません。 ひとつめ。 「処理がここまで通ってるよ」という確認は必要ですが、sampleという文言だけではどこかは分かりません。 せめて一意になる数字にしましょう。 ちなみに下記のように書くとそのプログラムの行数が出ます。 ``` echo __LINE__."\n";//重なってはいけないので改行を入れておく ``` ふたつめ。 確認しなければならない変数。 $mouthsという変数をグローバルスコープで下記のように確認したことで ``` //表示される //var_dump($mouths[0]); ``` getMouths()内で使えるぜ!と思ったかもしれませんが、根拠はどこですか? いずれにしても、本当に使えるかどうか確認しなければなりませんよね。 ``` function getMouths($itemperpage, $currentpage) { var_dump($mouths); //後略 } ``` こうしておけば、最初のNotice`PHP Notice: Undefined variable:`が出て気づけたでしょうね。 (エラー表示OFFだとnullかな) デバッグの仕方、本来確認すべき項目はきちんとおさえるようにしないと、デバッグがデバッグになりません。気をつけましょう。 **質問者さんは思ったとおりコードを動かせる域には到底達していません。** 蛇足: きちんと意味のある変数名つけてますか? mouthって「口」ですけど。 「口コミ」なら「reviews」ですね。レビュー。 他人が見ても意味が分かる内容にしておかないと、数ヵ月後自分が見たときも意味が分かりませんよ。 言語に限らず、下記のような記事はきちんと読んでおいて取り入れるようにしましょう。 * 良いコードを書く技術(まとめ) * プログラミング勉強を加速させる7つの習慣 * 初心者を戒めるPHP * 初心者プログラマが犯しがちな過ち25選