修正コード
PHP 4は、もうお疲れ様なので、PHP 5に移行してみましょう。
前回は、主にPHP 4流の書き方を指摘したので、これらをPHP 5らしい今の書き方に修正しています。またコードが理解しやすいように制御構造の見直しを行い、深いインデントにならないような工夫をしています。さらに今回は昨今のPHP界隈でよく使われているオートローダを使って、クラスファイルを自動で読み込むテクニックを組み込んでみました。
では、治療後の修正コードをどうぞ。
治療ポイント1. PHP 5の書き方へ
PHP 4の流儀で書かれた個所をPHP 5の書き方に変更しています。
診断編で指摘した個所以外では、メンバ変数やメソッドにアクセス修飾子を付けました。PHP 4では、メンバ変数はvar
キーワード、メソッドはアクセス修飾子なしで定義するしかなかったのですが、PHP 5では「public」「protected」「private」の3種類のアクセス権を設定することができます[1]。
PHP 4の形式で記述した場合はpublic
が設定されているのと同じ意味となります。修正コードでは、メンバ変数$nextPage
はLoginController
のみで利用されているのでprotected
を、メソッドについてはpublic
を設定しています。
どのアクセス権を用いるのが適切なのかは、構築するアプリケーションや利用するフレームワークなどによって変わります。特に制限がなければ、まずはprotected
を基本にして、公開する必要があればpublic
を、継承クラスからも隠す必要があればprivate
を用いるというのがよいでしょう。
治療ポイント2. 名前空間の設定
各PHPファイルに名前空間を設定しました。
名前空間にはAcme
をトップレベルに指定しています。Acme
はサンプルでよく使われる名前空間です。さらに、配置ディレクトリ(lib/
、controller/
、model/
)ごとにサブネームスペース(Acme\Lib
、Acme\Controller
、Acme\Model
)を指定しています。
これにより、LoginControllerクラスはAcme\Controller\LoginController
、LoginクラスはAcme\Lib\Login
が完全なクラス名となります。もしほかのライブラリを利用した際にLogin
というクラスが存在しても、名前空間が異なれば競合することはありません。
また、ファイル先頭付近にあるuse
文にて、名前空間のインポートを行っています。完全なクラス名を毎回記述するのは冗長ですが、この文により名前空間を省略したクラス名を利用することができます。
たとえば下記のようなコードであれば、Acme\Lib\Database
というクラスをDatabase
という名前で参照できるようになります。
治療ポイント3. 定数をクラス定数に変更
define
文にて定義している定数をクラス定数として定義しています。
define
文で定義した定数はグローバルな名前空間に属することになるので、アプリケーション全体で一意となる名前を付ける必要があります。これをクラス定数にすることで、クラス名が名前空間となり、同じ名前の定数でも異なるクラスに定義されれば、競合することはありません。
LoginController
クラスではLOGIN_ID
とPASSWORD
という定数をクラス定数として定義しています。もしも仮に、FooController
クラスにも同じLOGIN_ID
とPASSWORD
というクラス定数を定義されていても、クラス名が異なるので問題ありません。
クラス定数にする利点は、クラス固有の情報として役割がわかりやすくなるということが大きいですが、こうした名前の競合を避けるメリットもあるということを知っておくとよいでしょう。
治療ポイント4. オートローダの対応
各ファイルの先頭で記述していたrequire_once
文によるクラスファイルの読み込みをオートローダで行うようにしました。
オートローダは、参照しようとしたクラスが定義されていない場合に自動でクラスファイルを読み込む機構です。この処理は自分で書くこともできるのですが、ここではComposerに付属しているオートローダを利用します。
Composerのオートローダを利用するには、まずComposerをダウンロードします。下記コマンドを実行するとcomposer.phar
というファイルがダウンロードされます。
次にオートローダの設定をcomposer.json
というJSONファイルに記述します。
今回はPSR-4[2]によるオートロードを利用します。このcomposer.json
では、Acme\Lib
名前空間はlib/
ディレクトリ、Acme\Controller
名前空間はcontroller/
ディレクトリ、Acme\Model
名前空間はmodel/
ディレクトリからクラスファイルを読み込むことを指定しています。
このようにPSR-4では、名前空間と対応するディレクトリを記述することで柔軟にオートロードを設定することができます。
次にこのcomposer.json
に記述した内容をオートローダに反映するために次のコマンドを実行します。
最後に、このオートローダをLoginControllerで利用するように、require_once
文でオートローダを読み込みます。
これでComposerのオートローダが利用できるようになりました。クラスファイルはrequire_once
文で読み込まなくても、そのクラスを利用する際に自動で読み込まれるようになっています。
オートローダを用いることで、実際にそのクラスが利用される場面までクラスファイルの読み込みを遅らせることができるので、無駄なクラスファイルの読み込みを避ける効果もあります。
治療ポイント5. 制御構造の見直し
LoginController
クラスのexecute()
メソッドの実装について、制御構造の見直しを行いました。
execute()
メソッド内の制御構造のみを抜き出したのが下記です。ログイン処理を行うために3つのif
文による判定を経る必要があるため、実際のログイン処理は深いインデントの中で記述されています。
この制御構造を修正コードで組み直したのが以下です。それぞれのif
文にてログイン処理が成立しない場合はreturn
で処理を終了するようにしています。このようにすればインデントを深くする必要がなく、以後の処理では前のif
文の判定を気にしなくてよいので、理解しやすいコードとなります。
治療ポイント6. Login::auth()メソッドのシグネチャ見直し
Login
クラスのauth()
メソッドのシグネチャを変更しました。
元のコードでは、下記のようにUserModel
クラスオブジェクトを引数で受け取り、そこからログインIDとパスワードを取得していました。戻り値には、処理結果の正否だけをbooleanで返し、引数で渡された$userModel
に必要な値をセットしています。呼び出し元では、引数で渡した$userModel
を以降の処理で利用する形になっています。
auth()
メソッドでは、ログインIDとパスワードを外部から受け取り、データベースから取得したユーザ情報を返すという処理を行います。修正コードでは、この内容がわかりやすいようにシグネチャを変更して、ログインIDをパスワードを引数として受け取るようにしました。メソッド内部で、UserModel
クラスのオブジェクトを生成し、それを戻り値として返しています。
このようにすれば、メソッドのIN/OUTがシンプルになり、理解しやすくなります。元のコードで意図していた参照渡しを行う必要もありません。
治療を終えて
今回は、PHP 4のコードをPHP 5に変えるというテーマで診断を行いました。PHP 4のころは良いとされていた書き方も、PHP 5ではそう書く必要がなくなったり、むしろ良くない書き方となっている場合があります。オブジェクトの参照渡しなどは、他言語でプログラミングを行ってきた人のほうが書いてしまいがちなコードです。
PHPが進化してきたように、PHPコードも時代に合わせて変化していくことが必要となります。合わせて、PHPを取り巻くツールも変遷しています。今回紹介したComposerは、いまPHPで開発するなら必須とも言えるツールです。こうしたツールをうまく使うのも、今のPHPの書き方と言えるでしょう。
今回の診察はここまでです。また次回お会いしましょう。まだまだ寒い日が続くので風邪など引かれませんように。