[PHP] 名前空間

参考: PHP: 名前空間 - Manual

コードを書いてみる

<?php
$dummy = NULL;
namespace Foo\Bar;
?>

結果

Fatal error: Namespace declaration statement has to
 be the very first statement in the script in *** on line 3

名前空間より前に他の処理をしてはいけない。※declear文は除く

<?php
namespace dummy\one
{
  const CONSTANT = "one.\n";
}
namespace dummy\two
{
  echo \dummy\one\CONSTANT;
  const CONSTANT = "two.\n";
}
namespace{
  echo dummy\two\CONSTANT;
}

// echo "test" なんて名前空間外で何かをしようとするとE_ERRORになるよ
?>

結果

one.
two.

名前空間内のコードはセミコロン以下に書いてもいいし、 名前空間のあとの波括弧の中に書いても良い。 ただしグローバルなコードを名前空間つきのコードと組み合わせる場合は波括弧しか使えない。

※複数の名前空間を同一ファイル内で宣言するのは非推奨…ということは波括弧を使うような状況は基本的に止めたほうがいいと。

名前空間はディレクトリみたいなもの。 名前空間を宣言すると…作業ディレクトリは宣言した名前空間ですよ…と、 そんな感じの使い方。

<?php
namespace 
{
  $var = "生きる希望";
}
namespace 現実
{
  echo $var;
}

結果

生きる希望

普通の変数は名前空間とか関係なし。。

<?php
namespace // global
{
  const CONSTANT = "グローバル.\n";
}
namespace 名前空間
{
  const CONSTANT = "名前空間.\n";
  const TEST = "";
  echo \CONSTANT;
}
namespace 次元の狭間
{
  echo \名前空間\CONSTANT;
  echo CONSTANT;
  echo TEST;
  echo \TEST;
}

結果

グローバル.
名前空間.
グローバル.
TEST
Fatal error: Undefined constant 'TEST' in *** on line 17

名前空間内でグローバル定数などをコールするときは \ をつければOK

関数と定数(クラスは×)が名前空間内にない場合はグローバル空間を参照する。

で…次元の狭間で何が起きてるかというと…

echo TEST; で TEST が出力されるのは、未定義の定数を出力しようとしたときの仕様--文字列として出力する--によるもの。

しかし echo \TEST; が通らないのは 名前空間を指定するとその名前空間のみのものしか扱ってくれないから。

何が起きたのかとちょっと混乱してまった。。

<?php
namespace 地獄
{
  function mb_strlen(){
    echo "針の山はいかがですか.\n";
  }
}
namespace 天国
{
  echo \mb_strlen("ここは天国です"), "\n";
  echo \地獄\mb_strlen("ここは天国です");
}
namespace 現実
{
  echo mb_strlen("私の夢は現実です");
}

結果

14
針の山はいかがですか.
16

名前空間で定義済みの関数を定義しても大丈夫。通常の定義済みの関数はグローバル空間にあるから。

でも現実の名前空間でmb_strlen()をコールしたら、エラーが出るんじゃなくて定数の場合と同じくグローバル関数がコールされるのね。。こういう記述の仕方は止めたほうがよさそうかな?

<?php
namespace
{
  class C{
    public $var = "global";
  }
}
namespace 名前空間
{
  class C{
    public $var = "namespace";
  }
  function get($class){
    return new $class;
  }
  var_dump(get("C"));
  var_dump(get("名前空間\\C"));
  var_dump(get(__NAMESPACE__."\\C"));
}

結果

object(C)#1 (1) {
  ["var"]=>
  string(6) "global"
}
object(名前空間\C)#1 (1) {
  ["var"]=>
  string(9) "namespace"
}
object(名前空間\C)#1 (1) {
  ["var"]=>
  string(9) "namespace"
}

あれっ?と思ったけど変数は名前空間は関係なしだった…。 だから名前空間中で変数を参照してクラスを作ったりする場合は、かならず名前空間を指定するようにしないとダメ

エイリアス/インポート

クラス名のエイリアス・インポートができる。関数や定数はできない。

<?php
namespace foo;
class Cls{}
class Bar{}

namespace エイリアス・インポートはuse演算子を;
use foo\Cls as baz;
use foo\Bar; // use foo\Bar as Bar と等価

//上の二つをまとめて記述することも可能。カンマで区切って連結するだけ
//use foo\Cls as baz, foo\Bar;

var_dump(new baz); // baz は foo の Clsクラス
var_dump(new Bar); // Bar は foo の Barクラス

結果

object(foo\Cls)#1 (0) {
}
object(foo\Bar)#1 (0) {
}
<?php
namespace // global
{
  class Cls{}
}
namespace hoge
{
  use \Cls; // グローバル空間のClsクラスをインポート
  var_dump(new Cls);
}

結果

object(Cls)#1 (0) {
}
<?php
namespace a\b\c\d
{
  function ninja(){
    echo "….\n";
  }
  const JAPAN = "HENTAI.\n";
}
namespace a\b\c
{
  class d{}
}
namespace
{
  use a\b\c\d as alias;
  use a\b\c\d; // use a\b\c\d as d と等価
  alias\ninja();
  var_dump(new alias);
  echo alias\JAPAN;
  echo d\JAPAN;
  echo JAPAN;
}

結果

….
object(a\b\c\d)#1 (0) {
}
HENTAI.
HENTAI.
JAPAN

関数や定数のインポートはできないけど、名前空間のインポートはできる。なんかメッチャ混乱する。。

<?php
namespace テスト;

use テスト\クラス as 動的;
class クラス{}
$a = "動的";
new $a;

結果

Fatal error: Class '動的' not found in *** on line 7

インポートはコンパイル時に行われるので、動的な使い方はできない。

ちなみに namespace インポート; ってやったらエラーが出た。マルチバイト文字はきちんと対応してないのね。

<?php
namespace a\b\c;

use a\b\c\Foo as Bar;
class Foo{}

echo 'Bar | ';
new Bar ? print 'TRUE' : print 'FALSE' ;

echo "\nBar | False";
//new \Bar ? print 'TRUE' : print 'FALSE' ;
//グローバル空間のBarクラスは存在しないからFatal Error

結果

Bar | TRUE
Bar | False

マニュアルには…「インポートの影響が及ぶのは非修飾名および修飾名のみです。 完全修飾名は絶対的なものであり、インポートの影響を受けることはありません。」と書いてある。つまり… 最初にバックスラッシュつけると完全修飾名になるから、エイリアス・インポートは関係なくなるよ、と。

<?php
namespace useは一番外側で;
echo "これは出力されない";
function (){
  use foo as bar;
}

結果

Parse error: syntax error, unexpected T_USE in *** on line 5

use はコンパイル時に実行される。

<?php
namespace foo;
use foo\bar as hoge;
class hoge{}

結果

Fatal error: Cannot declare class foo\hoge
 because the name is already in use in *** on line 4

3行目と4行目を入れ替えてもE_ERROR。でも include などで別ファイルから読み込んだものは衝突しない。クラスと似たようなものか。。

その他こまかいコト

  • 完全修飾名は… \foo\bar のように最初に \ をつけた場合 と namespace\hoge のようにnamespace演算子を使った場合。
  • 非修飾名は… foo のような \無しの単発のもの
  • 修飾名は… foo\bar のような \無しの名前空間から始まって、その後に \ で以降の階層を記述している書き方。

    <?php
    namespace test;
    
    class hoge{}
    function test1(\test\hoge $obj){}
    function test2(hoge $obj){}
    function test3(\hoge $obj){}
    
    test1(new hoge);
    test2(new hoge);
    test3(new hoge);
    

結果

Catchable fatal error: Argument 1 passed to test\test3()
 must be an instance of hoge, instance of test\hoge given,
  called in *** on line 11 and defined in *** on line 7

タイプヒンティングと名前空間。test3() はとおらない…えらく長いエラーが出てきたな…

Share
関連記事