フリーランスのためのネットビジネス専門学校 ネットで独立開業を目指す人を応援
フリーランスのためのネットビジネス専門学校 ネットで独立開業を目指す人を応援

名前空間内クラスを変数で呼び出すときはグローバルプレフィックス演算子がいらない

ちょっと何言ってるのかよくわからない。

別の名前空間のクラスを呼び出す

別の名前空間のクラスを呼び出すときは、以下のように完全修飾名で記述します。

namespace FOO;
    class BAR{
        public function __construct(){echo 'BAZ';}
    }

namespace HOGE;
    new FOOBAR(); // BAZ
    new FOOBAR(); // Fatal error: Uncaught Error: Class 'HOGEFOOBAR' not found

newの次にある名前空間の頭のをグローバルプレフィックス演算子と言いますが、これを入れ忘れると、Class not foundのFatal errorが発生します。
なぜなら、その指定は名前空間HOGEからの相対パス、HOGEFOOBARを表しているからで、当然そのようなクラスは存在しないためエラーになるわけです。
Linuxや<script>タグなどのディレクトリ指定と同じように、頭にがあるかないかで絶対パス1か相対パスを識別しているということですね。

現象

ところでちょっとこれを見てくれ。

namespace HOGE;
    $class = 'FOOBAR';
    new $class; // BAZ ← ???

なんで?

さらに$classの中身は’FOO\BAR’でも’FOOBAR’でも’\FOO\BAR’でも’\FOOBAR’でもどれでも動きます。
いみがわからなすぎるぞ。

どうやら変数からnewした場合、常に完全修飾名であると見做されてしまうようです。

namespace FOO;
    class BAR{
        public function __construct(){echo 'BAZ';}
    }

    $class = 'BAR';
    new $class; // Fatal error: Uncaught Error: Class 'BAR' not found

    $class = 'FOOBAR';
    new $class; // こちらならOK

BARFOOからの相対パスFOOBARではなく、絶対パスBARとして扱われています。

実はマニュアルの名前空間と動的言語機能という項目に、これについての記載があります。
あるのですが、

動的なクラス名、関数名あるいは定数名においては修飾名と完全修飾名に差はないので、 先頭のバックスラッシュはなくてもかまいません。

何言ってるのかわかんねえ。

原因

さて、この差の原因ですが、直接べた書きしたときはコンパイル時に名前解決が行われ、変数を経由したときは実行時に行われる、という違いのようです。

namespace FOO;
    echo __NAMESPACE__; // FOO
    eval('echo __NAMESPACE__'); // "" ←

evalは実行時に評価が行われますが、その時点での__NAMESPACE__は空白になっています。

コンパイル時は名前空間に従って構文の解釈が行われます。
そして、コンパイル時に名前空間に関する情報は全て取り払われ、実行時には名前空間は無いものとして扱われます。

まあソースを読んだわけではなく現象からの推測ですが。
ソースコードリーディングは挫折した。

おまけ

名前空間内であれば、既存の組み込み関数やクラス、定数などと被る名前であっても堂々と命名できます。
わかりにくいのでやめたほうがいいですが。

namespace FOO;
    function printf(){}
    class stdClass{}
    const PHP_VERSION = '6.0.0';

そして、何故かごく一部の定数だけ例外があります。

namespace FOO;
    const NULL = 1; // Fatal error: Cannot redeclare constant NULL

NULL・TRUE・FALSE・ZEND_THREAD_SAFE・ZEND_DEBUG_BUILDの5定数だけは、名前空間内であろうとも定義することができません。
前三つはわかるとしても、後ろの二つはなんぞ?

あと言語構造などのキーワードは関数名として使えません。

namespace FOO;
    function print(){} // Parse error: syntax error, unexpected print
    function null(){} // こっちは使える

これに関する記載はユーザノートしか見当たらなかったんだけど、マニュアルにはどこかに記載はないのだろうか。

その他

別名前空間の変数を見たいときはどうすればいいんだっけ。

namespace FOO;
    const BAR = 1;
    $baz = 1;

namespace HOGE;
    echo constant('FOOBAR'); // 1
    echo FOO$vaz; // syntax error

  1. 正確にはルート相対パス 

コメント

記事に戻る

コメントを残す