LaravelなどのPHPを使ったフレームワークを使っていると、ダブルコロン2つの後ろに、classがついた「クラス名::class」といった表記を目にすることがあります。
なんだろうと思って、PHPのマニュアルで調べてみても、そこには普段使わないような専門用語がたくさん出てきて、結局よくわからないまま、、ということがあります。
でも、それらの専門用語が具体的に何のことを言っているのか?を理解すれば比較的簡単です。
実際、もともとは何かの処理(やりたいこと)が先にあって、後から、この処理はこう呼ぼうというように名前がつけられるのが一般的な流れなので、専門用語を覚えるよりも処理の中身を理解する方が大切です。
ここでは、「::class」と、それ関連する専門用語「完全修飾名」「名前空間」「名前解決」について実例を用いてわかりやすく解説しています。
::classとは何か?
::classとは、クラスの完全修飾名を文字列として取得するための記述で、PHP5.5から導入されたものです。PHP8.0以降は、オブジェクト(インスタンス)に対しても ::class を使って、そのクラスの完全修飾名を取得することができます。
例えば、名前空間「App\Service」の中の「TestClass」の完全修飾名は「App\Service\TestClass」です。
このため、名前空間「App\Service」の中で「echo TestClass::class」を実行すると「App\Service\TestClass」が返ってきます。
完全修飾名とは何か?
完全修飾名とは、相対的でない、グローバル空間のクラス名のことを指します。グローバル空間とは名前空間の外のことです。
名前空間がない場所で、対象のクラスを呼び出したい場合は、グローバル空間のクラス名を記述する必要があります。こうすることでどのファイルからでも指定したクラスを呼び出すことができます。
例えば、以下のように名前空間 App\Service の中で、クラス TestClass を定義したとします。このとき、完全なクラス名は App\Service\TestClass です。
namespace App\Service;
class TestClass{
public static function greeting(){
echo "Hello!";
}
}
名前空間とは?
名前空間とは、処理を記述している場所に名前をつけることを言います。namespace で指定します。上記の例では、 App\Serviceが名前空間になります。
本来、メソッド名は重複することができず、1つのプロジェクトの中で、重複して定義するとコンパイル時にエラーになります。
しかし、名前空間(namespace)を使うことで、同じ関数名を使うことができます。
例えば、以下のようにaaa.phpとbbb.phpの2つのファイルがあるとします。どちらもTestClassと greetingメソッドを定義しています。
しかし、冒頭の名前空間が App\Aaa と App\Bbb で異なるため、エラーにならずに使うことができます。
namespace App\Aaa;
class TestClass{
public static function greeting(){
echo "Hello! Aaa";
}
}
namespace App\Bbb;
class TestClass{
public static function greeting(){
echo "Hello! Bbb";
}
}
この場合、それぞれの完全修飾名(完全なクラス名)とクラス外からのメソッドの呼び出しは、以下のようになります。
ファイル名 | 完全修飾名 | クラス外からのメソッドの呼び出し |
---|---|---|
aaa.php | App\Aaa\TestClass | App\Aaa\TestClass::greeting(); |
bbb.php | App\Bbb\TestClass | App\Bbb\TestClass::greeting(); |
ちなみに、「\」がつかない TestClass のようなクラス名を、被修飾名 と言います。 冒頭に修飾するものが何もついていないので、そのままの意味です。
::classの使い方
名前空間、完全修飾名が何かわかったところで、実際に「::class」を使ってその便利さを確認してみます。
以下のような名前空間 App\Aaa の中で定義されているクラス TestClass の完全修飾名を確認したい場合は、「echo TestClass::class;」とします。
すると、App\Aaa\TestClass を返してくれます。つまり、自分がここでそのクラス名を使うとどのクラスを実行することになるのかを調べられるということです。
namespace App\Aaa;
class TestClass{
public static function greeting(){
echo "Hello!";
}
}
echo TestClass::class;
上記の例はシンプルですが、処理が複雑だったり、ファイルがたくさんある場合に、「::class」を使うことで呼び出したいクラスの完全な名前を確認したり、指定することができます。
エイリアスの設定
例えば、Laravelのエイリアスという機能で、名前空間の階層が深いクラスがあった場合に、省略名をつけて簡単に呼び出せるようにすることができます。
この指定方法は、完全なクラス名を文字列で指定する必要があります。
'省略名' => '完全なクラス名'
このときに、「::class」を使うと、指定したクラス名を文字列として呼び出せるので、記述がわかりやすくなります。
'Request' => Illuminate\Support\Facades\Request::class,
「::class」をつけずに「Illuminate\Support\Facades\Request」としてしまうと、文字列ではなく、そのクラス自体にアクセスしようとするため、正しく設定ができません。
名前解決
「::class」の説明で頻出する専門用語に「名前解決」があります。これは、PHPが完全なクラス名(完全修飾名)を自動で取得する処理のことです。
例えば、以下のように2つのクラスが定義してある場合、名前空間 App\Bbb の中で、「TestClass」のgreetingメソッドを呼び出す場合、「TestClass::greeting();」と記述すれば実行できます。
このとき、PHPは、与えられた「TestClass」がどのクラスのことを指しているのかを探します。そして、「App\Bbb\TestClass」だと判定して、App\Bbb\TestClass::greeting() を実行します。
完全なクラス名は何か?という問題を解決するので、「名前解決」と言います。
namespace App\Aaa;
class TestClass{
public static function greeting(){
echo "Hello! Aaa";
}
}
namespace App\Bbb;
class TestClass{
public static function greeting(){
echo "Hello! Bbb";
}
}
echo TestClass::greeting();
::classは完全なクラス名を返す処理です。すなわち、名前を解決しているので、::classは名前解決を行うための手段の一つということです。
グローバル名前空間と最初のバックスラッシュ 「\クラス::」
最後に、名前空間についてもう少し補足しておきます。「::class」を使えば、完全修飾名を返してくれますが、そこで返ってきたクラス名をそのまま、別の名前空間で使うと、それとはまた別のクラスを指すことになってしまいます。
例えば、以下のようなApp\Aaa の中で、「TestClass::class」を使えば、 App\Aaa\TestClass が返ってきます。
namespace App\Aaa;
class TestClass{
public static function greeting(){
echo "Hello! Aaa";
}
}
echo TestClass::class; //出力: App\Aaa\TestClass
ここで、得られた完全修飾名を、以下の App\Baa の中でそのまま使うと、クラス名が変わってしまいます。
これは、「App\Aaa\TestClass::class;」と理由が分かるのですが、指定したクラスが App\Baa\App\Aaa\TestClass として名前解決されるためです。
そして、そんなクラスはないのでエラーとなるわけです。
namespace App\Bbb;
class TestClass{
public static function greeting(){
echo "Hello! Bbb";
}
}
echo App\Aaa\TestClass::class;
これを解決する方法として、名前空間の中など、どのファイルからでも同じクラス名を指定するには、冒頭に「\」バックスラッシュをつけ、「\名前空間\クラス名」のように指定します。
\App\Aaa\TestClass とすることで、名前空間 App\Baa の中であっても、\App\Aaa\TestClass として認識できるわけです。
関数の呼び出し実例
<?php
namespace App\Aaa;
class TestClass{
public static function greeting(){
echo "Hello! Aaa";
}
}
echo TestClass::greeting(); //出力: Hello! Aaa
?>
<?php
namespace App\Bbb;
class TestClass{
public static function greeting(){
echo "Hello! Bbb";
}
}
echo TestClass::greeting(); //出力: Hello! Bbb
echo \App\Aaa\TestClass::greeting(); //出力: Hello! Aaa
?>