5分で理解するPHPのnamespaceとuseの使い方

PHPのライブラリなどで、しばしばusenamespaceといった記述を見かけます。今まではわりと適当に使っていたのですが、それではまずいと思い、きちんと調べてみました。

その調べた内容を簡潔にまとめれば、同じような疑問点を持つ方のお役に立てるのではないかと思い、記事にしました。なお、なるべく短くまとめるために、扱うのはクラスだけになります。

使用したPHPのバージョンは7.0.2になります。

問題点: クラス名の衝突

まずは、namespaceを使わない場合に起こりえる問題点を示します。

2つのPHPファイル、lib1.phpとlib2.phpがあるとします。この2つのファイルにはそれぞれFooというクラスと、get_fooというメソッドが定義されていたとします。

・lib1.php

<?php
class Foo {
    public function get_foo() {
        return 'lib1.foo';
    }
}

・lib2.php

<?php
class Foo {
    public function get_foo() {
        return 'lib2.foo';
    }
}

ここで、これらの2つのPHPファイルを読み込んで、Fooクラスのインスタンスを生成してget_fooメソッドを実行してみます。

<?php
require_once 'lib1.php';
require_once 'lib2.php';
$foo = new Foo();
echo $foo->get_foo() . "\n";

すると、以下のようにFatal errorが発生します。

Fatal error: Cannot declare class Foo, because the name is already in use in .../lib2.php on line 3

要は、lib1.phpでFooクラスを定義していて、lib2.phpでもFooクラスを定義しているから、クラス名が重複していて怒られているんですね!

解決方法: namespaceを利用

それでは、先ほどのクラス名が衝突した問題点を、namespaceを使って解決してみます。そのために、lib1.phpとlib2.phpに、namespace xxx;という行を追加します。

・lib1.php

<?php
namespace Lib1;  // これを追加
class Foo {
    public function get_foo() {
        return 'lib1.foo';
    }
}

・lib2.php

<?php
namespace Lib2;  // これを追加
class Foo {
    public function get_foo() {
        return 'lib2.foo';
    }
}

そして、これら2つのファイルを読み込んで、先ほどと同様にget_fooメソッドを実行してみます。

先ほどの例だと、Fooクラスのインスタンスを生成するときに、$foo = new Foo();としました。今回は、lib1.phpとlib2.phpにnamespaceを追加したので、lib1.phpのFooクラスのインスタンスを生成は$foo = new Lib1\Foo()と書くことができます。また、lib2.phpのFooクラスのインスタンスは$foo = new Lib2\Foo()で生成できます。

<?php
require_once 'lib1.php';
require_once 'lib2.php';
// $foo = new Foo();
$foo = new Lib1\Foo();
echo $foo->get_foo() . "\n";  // 「lib1.foo」と出力します。

$foo = new Lib2\Foo();
echo $foo->get_foo() . "\n";  // 「lib2.foo」と出力します。

つまり、lib1.phpとlib2.phpにnamespaceを指定したので、同じFooクラスでも、Lib1というnamespace(名前空間)に属するFooクラスと、Lib2というnamespaceに属するFooクラスで、区別できるようになったということです。これで、クラス名の衝突による問題は解決できました!

useでエイリアスを作成

最後にuseを使用してみます。その前に、lib1.phpを修正します。具体的には、namespaceを長くして、Foo2クラスとFoo3クラスを追加してみます。(※これ以降、lib2.phpはでてきません。)

・lib1.php

<?php
namespace Foo\Bar\Baz\Lib1;  // 長い。。。
class Foo {
    public function get_foo() {
        return 'lib1.foo';
    }
}

class Foo2 {
    public function get_foo() {
        return 'lib1.foo2';
    }
}

class Foo3 {
    public function get_foo() {
        return 'lib1.foo3';
    }
}

先ほどのnamespaceの例のように、lib1.phpを読み込むと、FooクラスはFoo\Bar\Baz\Lib1\Foo、Foo2クラスはFoo\Bar\Baz\Lib1\Foo2、Foo3クラスはFoo\Bar\Baz\Lib1\Foo3でアクセスすることができます。

<?php
require_once 'lib1.php';
$foo = new Foo\Bar\Baz\Lib1\Foo();
$foo2 = new Foo\Bar\Baz\Lib1\Foo2();
$foo3 = new Foo\Bar\Baz\Lib1\Foo3();
echo $foo->get_foo() . "\n";  // 「lib1.foo」と出力します。
echo $foo2->get_foo() . "\n";  // 「lib1.foo2」と出力します。
echo $foo3->get_foo() . "\n";  // 「lib1.foo3」と出力します。

なんだか、Foo\Bar\Baz\Lib1\がいっぱい出現して、面倒な感じですよね。。。

ここで登場するのがuseです。useを使うと、Foo\Bar\Baz\Lib1というnamespace(名前空間)のエイリアスを作成し、Lib1で参照できるようになります!先ほどのコードはuseを使って、以下のように修正できます。

<?php
require_once 'lib1.php';
/*
$foo = new Foo\Bar\Baz\Lib1\Foo();
$foo2 = new Foo\Bar\Baz\Lib1\Foo2();
$foo3 = new Foo\Bar\Baz\Lib1\Foo3();
*/
use Foo\Bar\Baz\Lib1 as Lib1;  // Foo\Bar\Baz\Lib1を、Lib1で参照できるようにエイリアスを作成します。
$foo = new Lib1\Foo();
$foo2 = new Lib1\Foo2();
$foo3 = new Lib1\Foo3();
echo $foo->get_foo() . "\n";  // 「lib1.foo」と出力します。
echo $foo2->get_foo() . "\n";  // 「lib1.foo2」と出力します。
echo $foo3->get_foo() . "\n";  // 「lib1.foo3」と出力します。

useを使ってエイリアスを作成したら、コードがすっきりしました!

ちなみに、この例だとuseのas以降を省略することもできます。(※asを使うと、作成するエイリアスの名前をLib1以外にすることができます。)

// use Foo\Bar\Baz\Lib1 as Lib1;
use Foo\Bar\Baz\Lib1;

また、エイリアスでnamespaceだけではなくて、クラスなどのエイリアスも作成することができます。

use Foo\Bar\Baz\Lib1\Foo;
use Foo\Bar\Baz\Lib1\Foo2;
use Foo\Bar\Baz\Lib1\Foo3;
// PHP7以降は以下の記述も使えます。※asの省略も可能です。
// use Foo\Bar\Baz\Lib1\{Foo as Foo, Foo2 as Foo2, Foo3 as Foo3};
$foo = new Foo();
$foo2 = new Foo2();
$foo3 = new Foo3();

以上、5分で理解できるように、簡潔にまとめてみました!

この記事が役に立った場合、シェアしていただけると励みになります!!