前書き
名前空間は、ある程度以上の規模のプログラムや、会社さんなど「複数のプロジェクトが動いている」システムにおいて、とても重要な役割を担います。
http://php.net/manual/ja/language.namespaces.php
特に最近、フレームワークを使っての開発が増えていますが、フレームワークにおいて名前空間は「必ず使う」機能になりますので、その基礎をしっかりと理解しておくとよいでしょう。
名前空間の基本
https://www.php.net/manual/ja/language.namespaces.rationale.php
https://www.php.net/manual/ja/language.namespaces.definition.php
https://www.php.net/manual/ja/language.namespaces.definitionmultiple.php
https://www.php.net/manual/ja/language.namespaces.nested.php
名前空間を使うことによって、従来名前の衝突を避けるために使っていた、長いクラス名や関数名などを避ける事ができます。
名前空間を宣言するには、キーワード namespace を使用します。名前空間を含むファイルでは、他のコードより前にファイルの先頭で名前空間を宣言しなければなりません。 ただし declare キーワードは例外です。
PHPの名前空間では、(抽象クラスやトレイトを含む)クラスとインターフェイス、関数、そして定数をひとまとめにして扱うことができます。
同一の名前空間を複数のファイルで定義することができます。 これにより、ひとつの名前空間の内容をファイルシステム上で分割することができます。
複数の名前空間を同一ファイル内で宣言することもできます。
ディレクトリやファイルと同様、PHP の名前空間においても名前空間の階層構造を指定することができます。
名前空間の使用法
https://www.php.net/manual/ja/language.namespaces.basics.php
https://www.php.net/manual/ja/language.namespaces.dynamic.php
https://www.php.net/manual/ja/language.namespaces.nsconstants.php
PHP がどのようにしてコード中の要素の名前空間を知るのかを理解しておくことが重要です。
PHP の名前空間内の要素についても同じ理屈があてはまります。 たとえば、クラス名を参照するには次の方法があります。
「同じ名前空間に存在する(または、その名前空間の階層構造配下のものを使う)」場合、相対的な書き方でアクセスをすることができます。
先頭バックスラッシュ \ で始まる、「完全修飾名」を指定することで、ファイルシステムでいう「絶対パス」のような書き方でアクセスをすることができます。 名前空間内で namespace 演算を使うと「現在の名前空間」を明示的に指定する事ができます。クラスでの self 演算子を思い浮かべるとよいでしょう。
「完全修飾名」を指定する書き方の1つになりますが、「動的なアクセス」も可能です。
動的にアクセスする場合は、 文字列で組み立てる、 NAMESPACE 定数を使う、 ::class を使った完全修飾クラス名の解決 などの方法があります。 文字列で組み立てる場合は、バックスラッシュのエスケープに注意しましょう。
動的なクラス名、関数名あるいは定数名においては修飾名と完全修飾名に差はないので、 先頭のバックスラッシュはなくてもかまいません。 また、名前空間の名前は、大文字小文字を区別しない事も覚えておきましょう。
名前空間のエイリアスとインポート
https://www.php.net/manual/ja/language.namespaces.importing.php
use 演算子によるインポート/エイリアス
use キーワードの宣言は、ファイル内の一番外側のスコープ (グローバルスコープ) あるいは名前空間宣言の中で行わなければなりません。
同じ namespace から複数のクラスや関数そして定数をインポートする際には、 それらをひとつの use にまとめることができます。
## グローバル空間
https://www.php.net/manual/ja/language.namespaces.global.php
https://www.php.net/manual/ja/language.namespaces.fallback.php
名前空間の定義がない場合、すべてのクラスや関数の定義はグローバル空間に配置されます。 これは、名前空間に対応する前の PHP がサポートしていた空間です。 名前の先頭に \ をつけると、 名前空間の内部からであってもグローバル空間の名前を指定することができます。
名前解決の流れ
https://www.php.net/manual/ja/language.namespaces.rules.php
名前の解決は、以下の順番で行われます。
- 完全修飾名は、そのまま解釈されます(先頭のバックスラッシュは除去されます)
- 相対名(
namespace
で始まる識別子)は、namespace
を現在の名前空間に置き換えて解釈します - 修飾名(
A\B
のように、先頭にバックスラッシュがなく途中にバックスラッシュがあるもの )の場合- インポートテーブル(use 演算子)がある場合、use演算子の指定に従って解釈します
- インポートテーブルがない場合、現在の名前空間を名前の先頭に付加して解釈します
- 非修飾名(バックスラッシュを含まないもの)の場合
- インポートテーブル(use 演算子)がある場合、use演算子の指定に従って解釈します
- インポートテーブルがなく、名前がクラス(やインタフェース、トレイトなどのシンボル)の場合、現在の名前空間を先頭に付加して解釈します
- インポートテーブルがなく、名前が関数や定数を参照している場合
- 現在の名前空間を先頭に付加して解釈します
- 「現在の名前空間を先頭に付加して解釈」して存在しない場合、グローバル空間として解釈します
このコラムに関連するコードはこちらになります
https://github.com/php-engineer-examination/php8_column_expert/blob/main/src/035_1.php
https://github.com/php-engineer-examination/php8_column_expert/blob/main/src/035_2.php
https://github.com/php-engineer-examination/php8_column_expert/blob/main/src/035_3.php
https://github.com/php-engineer-examination/php8_column_expert/blob/main/src/035_4.php
https://github.com/php-engineer-examination/php8_column_expert/blob/main/src/035_5.php
https://github.com/php-engineer-examination/php8_column_expert/blob/main/src/035_6.php
https://github.com/php-engineer-examination/php8_column_expert/blob/main/src/035_7.php
https://github.com/php-engineer-examination/php8_column_expert/blob/main/src/035_8.php