クラス名の重複(衝突)

PHPStormでコードを書いている時に以下のような警告が出ました。

Other declaration of class Foo exist at foo1.php less…
The inspection can produce two types of warnings:
Undefined class: Declaration of referenced class is not found in built-in library and project files.
Multiple declarations: this version of IDE *will* have problems with completion, member resolution and inheritance analysis for all classes that have multiple definitions in project files (regardless of includes).

ざっくり訳すと、

クラスFooの宣言はfoo1.phpに存在します。
検査では、次の2種類の警告が生成されます。
未定義クラス:参照されたクラスの宣言は、組み込みのライブラリおよびプロジェクトファイルには見つかりません。
複数の宣言:このバージョンのIDE *は、プロジェクトファイルに複数の定義を含むすべてのクラス(包含に関係なく)の補完、メンバーの解決、継承解析に問題があります。

とある。要はクラス名が他のファイルで同じ名前のものがあるので、衝突が発生する可能性があるよということ。さすがPHPStorm、優秀。しかし、衝突を避けなければいけないので、そこで名前空間(namespace)を使うことにしました。

名前空間(namespace)とは?

今さらながら名前空間(namespace)についての定義。

名前空間(なまえくうかん)はNamespaceの訳語で、名前の集合を分割することで衝突の可能性を低減しつつ参照を容易にする概念である。

引用:Wikipedia「名前空間」

PHPでも名前空間(namespace)は、version5.3以上であれば使用できます。
以下に実装例。

<?php
class Foo {
	public function getFoo () {
		return 'foo1.php file';
	}
}
<?php
class Foo {
	public function getFoo () {
		return 'foo2.php file';
	}
}

この2つのPHPファイルを読み込みます。

<?php
require_once 'foo1.php';
require_once 'foo2.php';

このファイルを実行してみるとFatal Errorで動作しません。以下のようなエラーログが出力されました。

Fatal error:  Cannot redeclare class Foo in /var/www/wordpress/job/foo2.php on line 2

「foo2.phpにFooクラスを再宣言できません。」と怒られてしまいます。これを利用できるようにするために名前空間(namespace)の設定を行います。

名前空間(namespace)の設定

先程の「foo1.php」「foo2.php」の2つのPHPファイルの先頭にnamespaceキーワードを記述します。

<?php
namespace Foo1;

class Foo {
	public function getFoo () {
		return 'foo1.php file';
	}
}
<?php
namespace Foo2;

class Foo {
	public function getFoo () {
		return 'foo2.php file';
	}
}

この設定をすることでFatal Errorが出力されなくなりました。よかったよかった。名前空間(namespace)の設定を行うとインスタンスの作成時に名前空間(namespace)を指定しなければいけません。
以下、インスタンス生成した場合。

<?php
require_once 'foo1.php';
require_once 'foo2.php';

$foo1 = new \Foo1\Foo();

// 'foo1.php file' が出力されます
echo $foo1->getFoo();


$foo2 = new \Foo2\Foo();

// 'foo2.php file' が出力されます
echo $foo2->getFoo();

できた!\(^o^)/
それぞれのクラスで定義したメソッドを動作させることができました。

名前空間(namespace)が長くなった場合には「use」でエイリアス設定

例では、名前空間(namespace)が「Foo1」「Foo2」のような名前だったので特に違和感はなかったのですが、名前空間(namespace)が長かった場合にしんどくなってきます。

<?php
namespace FooBar\Bar\Baz\Foo1;

class Foo {
	public function getFoo () {
		return 'foo1.php file';
	}
}

名前空間(namespace)が長いとなると、インスタンス生成時の指定が以下のようになりますよね。

<?php
require_once 'foo1.php';

$foo1 = new FooBar\Bar\Baz\Foo1\Foo();

echo $foo1->getFoo();

そこでuse演算子を用いてエイリアス(別名)をつけることができるので、設定してみます。

<?php
require_once 'foo1.php';

use FooBar\Bar\Baz\Foo1;

$foo1 = new Foo1\Foo();

echo $foo1->getFoo();

これでOK。しかし、これでは別名というより名前空間(namespace)が縮まっただけで、「エイリアス(別名)」とは微妙に違うような……と思っていたら、as(Aliasの略だと思っているのですが、間違っていないですよね?)を使用すれば、以下のように設定ができるようです。

<?php
require_once 'foo1.php';

use FooBar\Bar\Baz\Foo1 as AnotherName;

$foo1 = new AnotherName\Foo();

echo $foo1->getFoo();

できた!\(^o^)/
他の言語でも名前空間(namespace)が出てくるけど、結構言語によってクセがあるように思える。基本的な考え方は同じだけど。