色々
includeしすぎたりauto_loadした際に、利用したいクラス名はわかるも、呼び出すと「名前空間が違う」と怒られます。
- 関連記事: 「名前空間とは」| PHP の PSR-0 と PSR-4 で autoloader の違いと名前空間の基礎 @ Qiita
TL; DR (今北産業)
- 定義済みのクラスや関数の一覧を取得して、該当する名前空間を確認しましょう。
-
get_declared_classes関数やget_defined_functions関数を使って確認できます。 - 以下が具体的なサンプルです。
sample.php
<?php namespace KEINOS\Sample; include('vendor/autoload.php'); include('Functions.php'); include('Classes.php'); print_r(get_declared_classes()); //宣言済みクラス一覧 print_r(get_defined_functions()); //定義済み関数一覧 /* ... */
TS; DR (Phar 化したら名前空間が歪んだ)
Hello Error!
ちょっとしたアプリを作成したので、配布する際に単一の実行可能な PHP ファイルとして配布できるように Phar 形式(PHPアーカイブ)でアーカイブしました。
以下が、Phar化(アーカイブ)される本体 PHP スクリプトです。index.php と Functions.php の2つのファイルが HelloWorld.phar としてアーカイブされ、$ php HelloWorld.phar を実行すると「Hello World.」と表示するだけのシンプルなものです。
<?php
namespace KEINOS\Sample;
include('Functions.php');
if (is_phar()) {
echo 'Hello World.' . PHP_EOL;
} else {
echo 'Running directly. Not a phar file.' . PHP_EOL;
}
<?php
namespace KEINOS\Sample;
function is_phar()
{
return strlen(Phar::running()) > 0 ? true : false;
}
実行時にアーカイブ状態であるかの確認、つまりアプリ自身が Pharとして実行されているか確認をするために is_phar ユーザ関数内で、Phar クラスのメソッドを呼び出しています。
しかし、アプリの本体内部で namespace(名前空間)を使っているため、次のエラーが発生しました。
$ php HelloWorld.phar
PHP Fatal error: Uncaught Error: Class 'KEINOS\Sample\Phar' not found in phar:///PATH/TO/YOUR/SAMPLE/PHAR/APP/HelloWorld.phar/src/Functions.php:7
問題のある Functions.php:7 行目というと return strlen(Phar::running()) > 0 ? true : false; です。ここで「Pharクラスが見つからないんっすけど?
」と怒られています。
Phar クラスは自分のスクリプト内では定義はしていないため、当然といえば当然のエラーです。
A Class With No Name Space ~ 名前空間のないクラス ~
では、問題の Phar クラスはどこに属しているのか。
私は、Phar アーカイブを行う際に便利なアーカイバー「Box」を利用しているのですが、てっきり Box の名前空間を使うのかと思っていたのですが、手当たり次第思いつく名前空間をつけても NG でした。
そこで、以下のように get_declared_classes()を使って定義済みのクラスを一覧表示させたところ、びっくり。
<?php
namespace KEINOS\Sample;
include('Functions.php');
print_r(get_declared_classes());
/*
if (is_phar()) {
echo 'Hello World.' . PHP_EOL;
} else {
echo 'Running directly. Not a phar file.' . PHP_EOL;
}
*/
でるわでるわ、たかがこんなプログラムなのに、こんなに裏で定義されていたのか、と。
何がビックリしたかって、そもそも Phar は PHP のコアなクラスであるため名前空間を持っていないことに一番ビックリでした。
まぁ、落ち着いて考えれば、そりゃそうです。
名前空間のないクラスの呼び出し方
最終的には、スクリプトを以下のように Phar クラスの前にバックスラッシュ(\)を加えてエラーを回避しましたとさ。トホホぃのほい。
<?php
namespace KEINOS\Sample;
function is_phar()
{
return strlen(\Phar::running()) > 0 ? true : false; // Phar -> \Phar
}
参考文献
- 「is it possible to get list of defined namespaces?」 @ StackOverflow
- 「get_declared_classes」 @ PHP.net