PHPの名前空間は、クラス、関数、定数を接頭辞の下に置き、その名前がほかの誰かのものと衝突しないようにします。ファイルの最初の文としてnamespace App\Models;と宣言し、ほかのファイルではそのクラスを\App\Models\Userとして参照するか、use App\Models\User;でインポートしてUserとだけ書きます。
名前空間の中では、UserはApp\Models\Userを意味します。User::classは何も作らずに完全な名前を文字列として返すので、ログやオートローダーに便利です。
1つのファイルに2つの名前空間
本物のプロジェクトでは、1つのファイルに1つの名前空間を置きます。自己完結したデモなら、それぞれを波括弧で包めば1つのファイルに複数の名前空間を書けます。どの名前空間にも属さないコードはnamespace { }に書きます。
完全な名前が違うので、Orderという2つのクラスが並んで存在できます。ライブラリをインストールし始めると名前空間が解決してくれるのが、まさにこの問題です。自分のOrder、決済ライブラリのOrder、PDFライブラリのOrderがもう衝突しません。
useでインポートし、asで別名を付ける
どこでも\Shop\Orderと書くのは煩雑です。ファイル(または名前空間のブロック)の先頭のuseは名前をインポートし、短い形で使えるようにします。2つのインポートが同じ短い名前で終わるときは、asで一方に別の名前を付けます。
useはファイルの残りの部分のために短い名前を作るだけです。ファイルを読み込んだりコードを実行したりはせず、クラスがまだ存在していてもいなくても同じように動きます。まとめてインポートすることもできます:use Shop\{Order, Invoice};。
use functionとuse const
名前空間の中の関数と定数は、use functionとuse constでインポートします。
グローバルなクラスにはバックスラッシュが必要
名前空間の中では、修飾のないクラス名はその名前空間からの相対で解決されるので、namespace App;の中のnew DateTime()はApp\DateTimeを探します。関数と定数は違い、App\strlenが存在しなければ、PHPはグローバルなstrlenにフォールバックします。クラスは決してフォールバックしません。
catch (\Error $e)にバックスラッシュが必要だったのも同じ理由です。付けなければPHPはApp\Errorを探し、本物のエラーには決して一致せず、スクリプトはキャッチされないErrorで止まってしまいます。上のように先頭にバックスラッシュを付けるか、ファイルの先頭にuse DateTime;を書いて直します。同じことが\Exception、\Throwable、そのほかすべての組み込みクラスに当てはまります。それらのキャッチについてはtry catchを参照してください。
オートロードとPSR-4
プロジェクトでは、各クラスが自分のファイルに置かれ、ファイルのパスが名前空間に従います。その規約がPSR-4で、名前空間の接頭辞が基準となるフォルダーに対応し、名前の残りがパスになります。spl_autoload_register()で登録したオートローダーは、クラスが最初に使われたときにそのクラスのファイルを読み込みます。このブロックは2つのクラスのファイルをディスクに書き出し、それらをオートロードします。
各クラスのファイルは、そのクラスが最初に必要になった瞬間に1回だけ読み込まれます。本物のプロジェクトではこの関数を自分で書くことはなく、composer.jsonの数行からComposerが生成します。
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
composer dump-autoloadのあとは、エントリーとなるスクリプトの最初にrequire __DIR__ . '/vendor/autoload.php';と1行書くだけで、すべてのApp\...クラスが必要に応じて読み込まれます。
エラーの原因になる名前空間のルール
namespaceはファイルの最初の文でなければなりません。その前に書けるのはdeclare(strict_types=1);とコメントだけです。useのインポートはファイルごとです。index.phpでクラスをインポートしても、includeしたファイルの中では短い名前は使えません。各ファイルに自分のuse行が必要です。useはファイルか名前空間のブロックのトップレベルに書きます。クラスの本体の中のuseは別の意味で、トレイトを取り込みます。- 文字列は決して解決されません。
$class = 'User'; new $class();はグローバルなUserを探します。完全な名前を、できればUser::classで保存しましょう。
最後のものは手早く確認しておく価値があります。
よくある質問
PHPの名前空間とは何ですか?
関連するクラス、インターフェース、関数、定数をまとめる接頭辞で、名前のためのフォルダーのようなものです。ファイルの先頭にnamespace App\Models;と書くと、そのUserクラスはApp\Models\Userになるので、ほかのライブラリのUserと衝突しません。
PHPのuseは何をしますか?
ファイルの先頭のuse App\Models\User;で、そのファイルでは完全な名前\App\Models\Userの代わりにUserと書けるようになります。何かを読み込んだりincludeしたりはしません。クラスのファイルを読み込むのはオートローダーの仕事です。use ... as Alias;で別の短い名前を選べます。
名前空間の中でClass not foundになるのはなぜですか?
namespace App;の中では、修飾のないクラス名は名前空間からの相対で解決されるので、new DateTime()はApp\DateTimeを探します。new \DateTime()と書くか、先頭にuse DateTime;を加えます。関数と定数は自動でグローバル名前空間にフォールバックしますが、クラスはしません。
PHPのクラス名の前のバックスラッシュは何ですか?
先頭のバックスラッシュは、名前をグローバル名前空間から始まる完全修飾名にします。\Exceptionは、コードがどの名前空間にあっても常にPHPの組み込みのExceptionです。付けなければ、名前は現在の名前空間とuseのインポートからの相対で解決されます。
名前空間はフォルダーやPSR-4とどう関係しますか?
PHP自体は名前空間をフォルダーと結びつけていません。結びつけるのがPSR-4という規約で、App\のような接頭辞をsrc/のようなディレクトリに対応させるので、App\Models\Userはsrc/Models/User.phpに置かれます。Composerのオートローダーがそれに従うので、両者はたいてい一致します。