修正コード
第1回目で診断したPHPコードについて、問題点を治療した修正コードを書いてみましょう。ポイントとしては、指摘してきた問題点を中心に、コードの分離、同じ処理の共通化を行い、そして今どきのPHPの書き方をエッセンスとして加えています。クラス化やライブラリ、フレームワークの利用も考えられるのですが、元のコードから乖離しすぎないように、関数にまとめる方法で書きました。
では、治療後の修正コードです。
治療ポイント1. コードの分離
まず、コードの構成を、設定、ロジック、ビューの3段階に分離しました。こうして分離しておくことで、それぞれの役割が明確になり、見通しの良いコードとなります。また、別ファイルで同じ記述を共有したい場合(設定などは多くの場合そうなります)、設定部分のみを別ファイルに切り出して、それぞれのPHPファイルでは設定ファイルをrequire_once
文で読み込むということもやりやすくなります。
それぞれの部分について解説すると、設定ではdefine
文を使って、設定値を定数として定義しています。こういった設定値はコードの中で変更するということはあまりないので、定数として定義しておくと「これは変更されない値だ」ということが明確になります。コードの中には数多くの値が登場するので、変更すべき値と変更しない値を区別するということも読みやすいコードを書くうえで大切になります。
ロジック部分では、まず関数定義を行い、そのあとにメインの処理を書いています。メイン処理は130行目から始まるのですが、わずか20行強と短くなっています。この中で、状態による分岐を行い、フォームからの投稿(POST)の場合は、doPost()
関数を実行してます。元のコードでは、switch
文にて条件分岐を行い、その中のcase
文の中で実際の処理を記述していたのですが、ここでは条件分岐と実際の処理を分離することで、どのような状態があり、どのような流れになるのかがはっきりとわかるようになっています。
そして、最後がHTMLを出力するビューです。基本的にはHTMLの記述を行い、動的にHTMLの出力を行う個所のみ、必要なPHPを入れるようにしています。HTMLの出力はprint
文をやめて、HTMLはそのままHTMLとして記述しています。元のコードよりかなり見やすくなったのではないでしょうか。
治療ポイント2. コードの簡素化
主にロジック部分になりますが、処理の見直しを行い、コードを簡素化していきました。
元のコードでは、$mode
変数で実行する処理を分岐していたのですが、実際はこの$mode
には2つの状態しかなく、それも「フォームを表示する場合」「フォームから値が送信されてくる場合」の2種類しかないため、$_POST
に値がない場合は前者、ある場合は後者として扱うことで$mode
変数自体をなくしました。
ほかには、各処理を関数化することで、関数内に処理を閉じ込めています。たとえば、元のコードではswitch
文とbreak
文をうまく(?)組み合わせて、エラー発生時に処理から抜けるというコードが多数あったのですが、関数にしたことで、素直にreturn
文で実装しています。
治療ポイント3. 今のPHPの書き方へ
2013年の今、このPHPコードを直すならということで、一部処理については、昨今のPHPでの書き方に変えています。
まずはDB処理について。今ではPDO(PHP Data Objects)を利用するのが一般的となっていますので、pg_*
関数はPDOを使った書き方に変えています。SQL文を実行する際は、利便性とセキュリティを考慮してプリペアドステートメントを利用しています。これも今の定石と言ってよいでしょう。
ほかには、現在時刻を得るのにDateTime
クラスを、PDOでのエラーハンドリングにて例外を、また配列の定義にてarray()
ではなく[]
(short array syntax)を利用しています。
治療ポイント4. Noticeへの対応
元のコードを実行すると、未定義定数の参照や連想配列に存在しないキーを参照したためにNoticeエラーが多数発生しています。Noticeエラーは警告が表示されるだけで、実行には影響がないのですが、こうした警告を無視することは、せっかくPHPが発した情報を無視することになり、本来修正すべき点を見落とすことになります。
修正コードでは、定数はちゃんとdefine
文について定義し、配列ではarray_key_exists()
関数にてキーの存在を確認してから参照するようにしています。
治療ポイント5. セキュリティへの配慮
SQLインジェクションやクロスサイトスクリプティング(XSS)といった攻撃に対する対応を行っています。SQLインジェクションに対してはプリペアードステートメントの利用、XSSに対してはhtmlspecialchars()
関数によるエスケープを行っています。htmlspecialchars()
関数の実行はビューの中では何度となく出てくるので、escapeHtml()
関数にまとめてしまって、変数を出力する場面ではこの関数を呼ぶようにしています。
まとめ
第1回と第2回では、2002年とかなり古いPHPコードについて見てきました。2013年の今では新規でこういったコードを書くということはないと思うのですが、まだまだひっそりと稼働していて、いつこういったコードにお目にかかるやもしれません。
このコードはある意味すごいです。関数にまとめたり、ロジックとビューの分離を行わずによくこのコードを書いたと感心します。このコードを読んですぐに動作イメージを描けるのならば、それはそれですごいのですが、誰もが理解しやすいコードにしておくことで、不具合の発見も気づきやすく、変更にも強いコードとなります。
修正コードはあくまで一例で、まだまだ手を加えていくことができます。特にビューについては本来別画面となる内容(フォーム画面と完了画面)を1ファイルに混在させているので、見通しが悪くなっています。ほかにも以下に挙げるように、手を入れるべき個所はいくつかあるのですが、それらは読者への課題としてみたいと思います。
- フォーム画面と完了画面とでファイルを分ける
- 設定、ロジック、ビューでファイルを分ける
- ライブラリやフレームワークの活用
初めての診断はいかがだったでしょうか。今後もこのような流れで、巷にある悩めるPHPコードを診断していきます。あなたの周りにあるPHPコードの投稿もお待ちしています。