$_GET, $_POST などの値を使用する場合、よくサンプルとして
php
1$str = isset($_POST['str']) ? $_POST['str'] : '';
のようにスーパーグローバル変数を直接扱っているものを見かけます。
php
1$str = $_POST['str'];
なんて記述は論外ですが、上の三項演算子のモノでも、IDE によっては「スーパーグローバル変数には直接アクセスしないでね。」と警告をクラってしまいます。
少し調べてみたのですが、理由は以下のようでした。
スーパーグローバル変数は、変更可能な変数であるため、直接アクセスすべきではない。
利便性も良いので、filter_input()
を利用することは嫌ではないのですが、警告内容に納得がいっていません。
スーパーグローバル変数に直接アクセスしない方がいい理由とはなんなんでしょうか?
できれば具体的な内容も交えて説明いただけると助かります。
少しとんがった回答でもありがたいです。よろしくお願いいたします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
ベストアンサー
$_GET
などに限らず、グローバル変数を多用することは、コードを密結合にしてしまいます。
たとえば、あるメソッドのユニットテストをするとしたときに、「リクエストパラメータは$request
引数で渡す」としておけば、その$request
さえ差し替えればうまくテストができます。
一方で、$_GET
に依存するままコードを書いていると、$_GET
を差し替えるという荒技を取らなければテストできませんし、さらに「$_GET
を書き換える」ことで動作するようなコードがあった場合、うまく動作しなくなってしまいます。
実際、フレームワークでも、スーパーグローバルをラッピングして、インスタンスメソッドとして実装していることが、よくあります。
投稿2017/01/29 03:22
総合スコア145930
0
maisumakun さんと raccy さんの回答で非常に理解が進みました。
スーパーグローバル変数に直接アクセスしない方がいい理由に関して、以下の通り理解したのでまとめておきます。
書き換え可能なグローバル変数を利用しない
プログラムを疎結合とするため。疎結合であるべき理由はググれ。
filter_input関数を利用する理由
filter_input関数はスーパーグローバル変数のただの代替ではない。
php
1<?php 2//test.php?a=a 3echo $_GET['a'] ;//a 4 5$_GET['a'] = 'b'; 6echo $_GET['a'] ;//b 7 8echo filter_input(INPUT_GET, 'a');//a 9
直接 HTTP header から値を取ってくるため、グローバル変数が変更されても影響を受けない。結果、めっちゃ疎。
投稿2017/01/29 05:10
編集2017/01/29 05:14退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
推奨されない理由はスーパーグローバル変数だからではなく変更可能なグローバル変数だからだと思われます。これはPHPだけではなく、他のプログラミング言語においてもグローバル変数はなるべく使用すべきでは無いとされています。
グローバル変数が使うべきでは無いという理由は、複数のモジュールやライブラリを呼び出すようなある程度の規模があるプログラムでは管理が難しくなるからです。
実際のアプリケーションを作成するとき、簡単なツールでなければ、機能の増加に伴いプログラムはどんどん大きくなっていきます。やがて一つのソースコードで管理することは不可能になります。そこで行うのはファイルの分割です。それぞれの機能を複数のファイルに分けて管理しやすくします。この時点でグローバル変数の扱いが難しくなります。いま書いているファイルとは別のファイルでグローバル変数を書き替えていた場合はどうなるでしょうか?また、実は名前が被っていてうまく動かなかったらどうなるでしょうか?ファイル間で同じグローバル変数を全く別の用途に使っていれば、きっと予想もしない動作をすることになるでしょう。
具体例を見てみましょう。呼び出す度に1ずつカウントしていく関数f()
を作成し、別のファイルother.phpとして用意したとします。other.phpのドキュメントには「関数f()
は呼び出す度に1から1ずつカウントする関数」と書いておきましょう。
other.php
PHP
1<?php 2$x = 1; 3function f() { 4 global $x; 5 return $x++; 6}
では、メイン側であるmain.phpで使ってみましょう。
main.php
<?php require_once('other.php'); $x = 2; var_dump(f()); var_dump($x);
果たしてこれは期待通りの動作でしょうか?main.phpをコーディングしているときにother.phpのソースコードは見ません。参考にするのはother.phpに関する「関数f()
は呼び出す度に1から1ずつカウントする関数」という情報だけです。しかし、実際はグローバル変数$x
の名前が被っているため、カウントは2から始まってしまいますし、$x
も3になってしまっています。このような動作を変数汚染といい、グローバル変数は最も汚染されやすい変数です。
この例は単純なため、一つのファイルにすれば問題ないと思うかも知れません。しかし、実際はもっとたくさんの処理が入るため、適切にファイルを分割しないと難しくなります。ファイルを分割すると、今度はグローバル変数が同じだった場合に問題が起きてしまうため、グローバル変数はコード全体を通してなるべく使うべきではありません。
さらに規模が大きくなると、プログラム全体をモジュール化して、ライブラリとして使用するようになります。よく使うような機能はライブラリとして分離しておくと再利用することも可能ですし、そのようなライブラリが多く公開されていて、誰でも利用できるようになっています。しかし、ライブラリのソースコードを一つ一つ見てから使用するには非現実的です。実際はライブラリのドキュメント、つまり「関数f()
は呼び出す度に1から1ずつカウントする関数」のような情報だけを参考にライブラリを使用することになります。
もし、ライブラリが上のような作りだった場合はどうなるでしょうか?ましてや、自分が作ったのでは無い誰かが作って公開しているライブラリを使う場合はどうなるでしょうか?もはや、安全にグローバル変数を使うことはできません。どのような動作をするのか予測することができなくなり、重大なバグのきっかけとなることでしょう。
実際の所、ライブラリの作者達はそのような危険性を知っているため、行儀の良いライブラリはグローバル変数を使うことが全く無いか、グローバル変数を使う場合は、ライブラリのドキュメントに明記しています。
話は変わってスーパーグローバル変数について考えましょう。$_POST
はPHP開発者であればスーパーグローバル変数であることはわかっているはずです。まさか、それを変更しようなどと言う人はいない…と思いたいところがそうでもありません。例えばPOSTで渡されたファイルを自動的に判断して便利になるように書きかえるようなライブラリを作ったとします。ファイルのエンコードを自動判断して、Shift_JISやEUC-JP等であったら、UTF-8に書きかえておくなんてあると便利だと思いませんか?ライブラリを使っても使わなくても便利なように$_POST
を書きかえておけばさらに便利だと思いませんか?もちんろ、グローバルへ数が汚染されてしまいますので、そのようなことはすべきではありません。しかし、自分が作った物ではないライブラリではそのような行儀が悪い実装をしている可能性があります。むしろ、自分が昔作ったライブラリでそのような行儀が悪い実装をしてしまっているかもしれません。そのようなときに、$_POST
を使おうとしたら、きっと予測ができない動作が起きてしまうかも知れません。
このように、グローバル変数はなるべく使うべきではありません。
投稿2017/01/29 03:59
総合スコア21737
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/01/29 04:31
0
$_GET
や$_POST
などにはユーザからの入力が入っています。
この入力には悪意のあるものが入っているかもしれません。
仮にJavaScriptでチェックしてあっても容易に回避できるので
信用してはいけません。
悪い例として、
php
1$str = isset($_POST['str']) ? $_POST['str'] : '';
で取得した$str
を他の利用者の画面にそのまま表示したとします。
$str
に
html
1<script type="text/javascript"> 2// 悪意のあるJavaScript 3</script>
のようなものが入っていた場合、そのままJavaScriptとして実行されてしまいますので、
<
を<
に変えるなどの処理が必要になります。
以上のような処理が必要であることを気づかせるための警告だと認識しています。
スーパーグローバル変数に直接アクセスしていても、
自分でちゃんとチェックしていれば無視してもいいと思います。
投稿2017/01/29 00:55
総合スコア30
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/01/29 02:00
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/01/29 04:23 編集
2017/01/29 04:26
退会済みユーザー
2017/01/29 05:10 編集