ここで、最初のOrderAdminの例に戻ります。リスト1とリスト2のOrderAdminそれぞれに名前空間を付与したクラスを作ります。最初のOrderAdminと区別するために、それぞれ別のクラス名とします。
- <?php
- namespace atmarkit\phplesson\chap20\classes\businesses;
- class OrderAdminName
- {
- public function __construct()
- {
- print("businesses/OrderAdminがnewされました<br>");
- }
- }
- <?php
- namespace atmarkit\phplesson\chap20\classes\consumers;
- class OrderAdminName
- {
- public function __construct()
- {
- print("consumers/OrderAdminがnewされました<br>");
- }
- }
これらのクラスを利用するために以下のようにrequire_onceとuseを記述したとします。
- <?php
- require_once("classes/businesses/OrderAdminName.php");
- require_once("classes/consumers/OrderAdminName.php");
- use atmarkit\phplesson\chap20\classes\businesses\OrderAdminName;
- use atmarkit\phplesson\chap20\classes\consumers\OrderAdminName;
- :
- :
このファイルを実行すると、以下のエラーとなります。
Fatal error: Cannot use atmarkit\phplesson\chap20\classes\consumers\OrderAdminName as OrderAdminName because the name is already in use in C:\xampp\htdocs\phplesson\chap20\useOrderAdmin.php on line 6
せっかく名前空間を導入しても、やはり名前が同じクラスを読み込むとエラーとなります。これを回避するために、クラス名に別名を付けます。それは、以下のように記述します。このphpファイルを作成、実行してください。
- <?php
- require_once("classes/businesses/OrderAdminName.php");
- require_once("classes/consumers/OrderAdminName.php");
- use atmarkit\phplesson\chap20\classes\businesses\OrderAdminName as OrderAdminBusiness; // (1)
- use atmarkit\phplesson\chap20\classes\consumers\OrderAdminName as OrderAdminConsumer; // (2)
- $orderAdmin = new OrderAdminBusiness(); //(3)
実行結果は以下の通りです。
businesses/OrderAdminがnewされました
ここでのポイントは、リスト8の(1)と(2)の「as」です。クラスをuseする際、asキーワードを使って別名を付けることができます。これを、「エイリアス」といいます。これによって、本来のクラス名が何であれ、このphpファイル内でのオリジナルな名前を付けることができます。構文としてまとめると以下のようになります。
use 名前空間\クラス名 as クラスの別名;
このエイリアスのおかげで、クラスを作る際にクラスの完全修飾名の重複だけ避ければ、自由にクラスを作ることができます。一方で、もしクラス名が重複していたとしても、それらのクラスを読み込む際に重複の解消を図ることができるというものです。
なお、asで別のクラス名が定義されている場合は、エイリアスの方を使います。リスト8では(3)が該当します。
先のコラムで関数と定数にも名前空間が付与できることに触れました。これら名前空間が付与された関数や定数をuseで読み込む場合は、クラスと異なり、以下のように記述します。なお、いずれの場合も「as 別名」はなくても構いません。
use function 名前空間\関数名 as 関数の別名; use const 名前空間\定数名 as 定数の別名;
名前空間を導入すると、確かにクラスを整理することが可能となります。しかし、問題が1つ発生します。それは、リスト8を見ても分かるように、クラスを利用する際にrequire_onceとuseの両方を記述しないといけないということです。
1つのクラスは1つのファイルに記述されているので、例えば、10個のクラスを利用するとなると、10行のrequire_onceと10行のuseを記述しなければなりません。この問題を解決する方法として「オートロード」機能がPHPには用意されています。これは、クラスを利用する際に、そのクラスファイルが読み込まれていなければ、こちらが指定した関数を自動で呼び出す、という機能です。
具体例を見ていきましょう。以下のautoload.phpを作成してください。
- <?php
- //オリジナルのオートロード関数。
- function myAutoload(string $classname): void // (1)
- {
- //クラス名を\で分割した配列を作成。
- $classNameArray = explode("\\", $classname); // (2)
- //ファイルパス用文字列変数を用意。
- $filepath = "";
- //分割されたクラス名配列をループさせながらファイルパスを生成。
- for($i = 1; $i < count($classNameArray); $i++) { // (3)
- $filepath .= "/".$classNameArray[$i];
- }
- //ファイルパスの前にドキュメントルートのパス、後に拡張子を追加。
- $filepath = $_SERVER["DOCUMENT_ROOT"].$filepath.".php"; // (4)
- //ファイルパスの先が正常ファイルかどうかを判定。
- if(is_file($filepath)) { // (5)
- //正常パスなら読込。
- require_once($filepath); // (6)
- }
- }
- //オートロード関数を登録。
- spl_autoload_register("myAutoload"); // (7)
(1)が自作したオートロード関数です。このような関数を作成し、(7)のようにspl_autoload_register()関数を使って自作したオートロード関数を登録することで、クラスを利用する際にそのクラスファイルが読み込まれていなければ、ここで登録したオートロード関数(ここでは、myAutoload()です)が自動呼び出しされる仕組みです。その際、引数として該当クラスの完全修飾名が渡ってきます。ですので、オートロード関数内は、引数であるクラスの完全修飾名を頼りに最終的にクラスファイルを読み込む処理を記述することになります。リスト9では(6)が該当します。
myAutoload()内の処理は基本的にコメントを読めば分かりますが、幾つか補足しておきましょう。
クラスの完全修飾名は、\で区切られています。この\を/に置き換えることでファイルパスに近いものができそうですが、そう簡単にはいきません。というのは、通常の命名方式を採るならば、\で区切られた最初がベンダー名となっており、2番目以降がファイルパスと一致するようになっています。そのため、この最初のベンダー名部分を取り除く必要があります。そのため、まず\で分割した配列を作成します(リスト9の(2))。
その配列を(3)でループさせながら文字列結合でパスを生成する方式を採っています。その際、配列の最初の要素(インデックス0)を含まないようにするためにカウンタ変数$iを1からスタートしています。この段階で、例えば、$classnameであるクラスの完全修飾名が「atmarkit\phplesson\chap20\classes\businesses\OrderAdminName」の場合は、ファイルパスを表す変数である$filepathは「phplesson/chap20/classes/businesses/OrderAdminName」となっています。この文字列の前にドキュメントルートパスと末に拡張子を付与します。それがリスト9の(4)です。
ドキュメントルートは定義済み変数の一つである$_SERVERにキーとしてDOCUMENT_ROOTを渡すことで取得できます。
最後に、このようにして生成したファイルパス先に実際にファイルが存在するかを念のためにチェックしているのがリスト9の(5)です。無事ファイルとして存在する場合、最終的に(6)でrequire_onceを実行してファイルを読み込みます。
最後に、このようなオートロードの仕組みを利用する方法を紹介しましょう。リスト8のuseOrderAdmin.phpをオートロードを利用したものに改良した以下のuseOrderAdminAuto.phpファイルを作成、実行してください。なお、変更したのは(1)の部分のみです。
- <?php
- require_once("autoload.php"); // (1)
- use atmarkit\phplesson\chap20\classes\businesses\OrderAdminName as OrderAdminBusiness;
- use atmarkit\phplesson\chap20\classes\consumers\OrderAdminName as OrderAdminConsumer;
- $orderAdmin = new OrderAdminBusiness();
(1)のように、require_onceするのは、オートロードが記述されたautoload.phpのみとします。一方、useは必要なクラス分全て記述します。こうすることで、require_onceの記述を一挙に減らすことができます。
最近のPHP開発では、「Composer」というパッケージ管理ツールを使うのが当たり前となっています。Composerの詳細解説は他に譲りますが、これは、PHPの各種ライブラリやフレームワークの依存関係を自動で解決し、それらのファイル類をコマンドだけで自動ダウンロードしてくれるツールです。
本稿で紹介した、オートロードの機能もこのComposerのコマンドを使えば、「autoload.php」を自動生成してくれます。Composerを使っている場合は、この自動生成されたautoload.phpを「require_once」して使うのが通常です。
今回で、本連載は終了です。20回という長きにわたって、ここまでお付き合いいただき、ありがとうございました。
PHPの解説といえば、HTMLやDBと組み合わせたいわゆるWebシステム構築のものが多い中、PHPの文法、構文に焦点を当てた本連載は珍しいのではないかと思います。
PHPの一番根幹の部分を解説する内容となっているので、小手先のテクニックではなく、PHPコーディング力を身に付けてもらえることを意識して執筆してきました。本連載の読者にそのような力が付いたのであれば、こんなにうれしいことはありません。
Copyright © ITmedia, Inc. All Rights Reserved.
HTML5�偽X 險倅コ九Λ繝ウ繧ュ繝ウ繧ー