FAQ: 名前空間について知っておくべきこと

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

この FAQ は 2 つに別れています。一般的な質問と、 深く理解するために有用な実装に関する質問です。

まずは一般的な質問。

  1. 名前空間を使わない場合、 何か注意すべきことはありますか?
  2. 名前空間内での内部クラスあるいはグローバルクラスの使用法は?
  3. 同じ名前空間にあるクラス、関数あるいは定数を使用する方法は?
  4. \my\name\name のような名前はどのように解決される?
  5. my\name のような名前はどのように解決される?
  6. 修飾されていない name のようなクラス名はどのように解決される?
  7. 修飾されていない name のような関数名/定数名はどのように解決される?

また、名前空間の実装を理解するために有用な実装の詳細は次のとおりです。

  1. インポートした名前が同一ファイルで定義されているクラスと衝突してはいけない
  2. 名前空間のネストはできない
  3. 動的な名前空間名 (クォートした名前) ではバックスラッシュのエスケープが必要
  4. バックスラッシュを含む未定義な定数を参照すると、致命的なエラーが発生する
  5. 特別な定数 NULL, TRUE, FALSE, ZEND_THREAD_SAFE そして ZEND_DEBUG_BUILD は上書きできない

名前空間を使わない場合、何か注意すべきことはありますか?

いいえ。これまで書いてきたコード、今後書く名前空間を含まないコードのいずれについても、 名前空間が何らかの影響を及ぼすことはありません。 お望みなら名前空間を使わないコードを書くこともできます。

例1 名前空間の外部にあるグローバルクラスへのアクセス

<?php
$a 
= new \stdClass;
?>

これは、機能的に次と同等です。

例2 名前空間の外部にあるグローバルクラスへのアクセス

<?php
$a 
= new stdClass;
?>

名前空間内での内部クラスあるいはグローバルクラスの使用法は?

例3 名前空間内からの内部クラスへのアクセス

<?php
namespace foo;
$a = new \stdClass;

function 
test(\ArrayObject $parameter_type_example null) {}

$a = \DirectoryIterator::CURRENT_AS_FILEINFO;

// 内部クラス/グローバルクラスの継承
class MyException extends \Exception {}
?>

同じ名前空間にあるクラス、関数あるいは定数を使用する方法は?

例4 名前空間内のクラス、関数あるいは定数へのアクセス

<?php
namespace foo;

class 
MyClass {}

// 現在の名前空間のクラスを引数の型として使う
function test(MyClass $parameter_type_example null) {}
// 現在の名前空間のクラスを引数の型として使うもうひとつの方法
function test(\foo\MyClass $parameter_type_example null) {}

// 現在の名前空間のクラスの継承
class Extended extends MyClass {}

// グローバル関数へのアクセス
$a = \globalfunc();

// グローバル定数へのアクセス
$b = \INI_ALL;
?>

\my\name\name のような名前はどのように解決される?

\ から始まる名前は常に見た目のままに解釈されます。 つまり \my\namemy\name であり、 \ExceptionException となります。

例5 完全修飾名

<?php
namespace foo;
$a = new \my\name(); // "my\name" クラスのインスタンスを作成します
echo \strlen('hi'); // "strlen" 関数をコールします
$a = \INI_ALL// $a に定数 "INI_ALL" の値を設定します
?>

my\name のような名前はどのように解決される?

名前にバックスラッシュを含むが先頭はバックスラッシュでない名前、たとえば my\name のような名前は 2 通りの方法で解釈されます。

別の名前に my というエイリアスを指定する import 文がある場合は、そのエイリアスが my\namemy 部分に適用されます。

それ以外の場合は、現在の名前空間が my\name の先頭に付け加えられます。

例6 修飾名

<?php
namespace foo;
use 
blah\blah as foo;

$a = new my\name(); // "foo\my\name" クラスのインスタンスを作成します
foo\bar::name(); // "blah\blah\bar" のstaticメソッド "name" をコールします
my\bar(); // "foo\my\bar" 関数をコールします
$a my\BAR// $a に定数 "foo\my\BAR" の値を設定します
?>

修飾されていない name のようなクラス名はどのように解決される?

バックスラッシュを含まない name のようなクラス名は 2 通りの方法で解釈されます。

別の名前に name というエイリアスを指定する import 文がある場合は、そのエイリアスが適用されます。

それ以外の場合は、現在の名前空間が name の先頭に付け加えられます。

例7 非修飾クラス名

<?php
namespace foo;
use 
blah\blah as foo;

$a = new name(); // "foo\name" クラスのインスタンスを作成します
foo::name(); // "blah\blah" クラスのstaticメソッド "name" をコールします
?>

修飾されていない name のような関数名/定数名はどのように解決される?

バックスラッシュを含まない name のような関数名/定数名は 2 通りの方法で解釈されます。

まず、現在の名前空間が name の先頭に付け加えられます。

現在の名前空間に name という関数あるいは定数がない場合は、 グローバル関数あるいは定数に name があればそれを使用します。

例8 非修飾関数/定数名

<?php
namespace foo;
use 
blah\blah as foo;

const 
FOO 1;

function 
my() {}
function 
foo() {}
function 
sort(&$a)
{
    \
sort($a); // グローバル関数 "sort" をコールします
    
$a array_flip($a);
    return 
$a;
}

my(); // "foo\my" をコールします
$a strlen('hi'); // "foo\strlen" が存在しないので、グローバル関数 "strlen" をコールします
$arr = array(1,3,2);
$b sort($arr); // "foo\sort" 関数をコールします
$c foo(); // calls function "foo\foo" - import is not applied

$a FOO// sets $a to value of constant "foo\FOO" - import is not applied
$b INI_ALL// sets $b to value of global constant "INI_ALL"
?>

インポートした名前が同一ファイルで定義されているクラスと衝突してはいけない

次のようなスクリプトの組み合わせは、正当なものです。

file1.php

<?php
namespace my\stuff;
class 
MyClass {}
?>

another.php

<?php
namespace another;
class 
thing {}
?>

file2.php

<?php
namespace my\stuff;
include 
'file1.php';
include 
'another.php';

use 
another\thing as MyClass;
$a = new MyClass// 名前空間 another のクラス "thing" のインスタンスを作成します。
?>

MyClass クラスが名前空間 my\stuff にあるとはいえ、名前の衝突はありません。 MyClass の定義は別のファイルにあるからです。 しかし、次の例は名前の衝突による致命的なエラーとなります。 MyClass の定義が同じファイル上の use 文で行われているからです。

<?php
namespace my\stuff;
use 
another\thing as MyClass;
class 
MyClass {} // fatal error: MyClass conflicts with import statement
$a = new MyClass;
?>

名前空間のネストはできない

PHP では名前空間のネストはできません。

<?php
namespace my\stuff {
    namespace 
nested {
        class 
foo {}
    }
}
?>
しかし、それっぽいことをするのは簡単です。次のようにすればいいのです。
<?php
namespace my\stuff\nested {
    class 
foo {}
}
?>

動的な名前空間名 (クォートした名前) ではバックスラッシュのエスケープが必要

バックスラッシュは文字列のエスケープ文字として使われることに注意しましょう。 文字列の中で使う際にはバックスラッシュを二重に書く必要があります。 そうしないと、予期せぬ結果を引き起こしてしまいます。

例9 ダブルクォートで囲んだ文字列内で名前空間名を扱う際の危険

<?php
$a 
"dangerous\name"// ダブルクォートの中では \n が改行文字になってしまいます!
$obj = new $a;

$a 'not\at\all\dangerous'// これなら大丈夫です
$obj = new $a;
?>
シングルクォートで囲んだ文字列内では、 バックスラッシュによるエスケープシーケンスをより安全に使うことができます。 しかし、文字列内では常にバックスラッシュをエスケープする習慣をつけておくことをお勧めします。

バックスラッシュを含む未定義な定数を参照すると、致命的なエラーが発生する

未定義の定数のうち FOO のような修飾されていないものは、 PHP が FOO を定数の値と解釈したという notice が発生します。 修飾あるいは完全修飾形式の定数、つまりバックスラッシュを含む定数の場合、 それが未定義なら致命的なエラーが発生します。

例10 未定義の定数

<?php
namespace bar;
$a FOO// notice - undefined constants "FOO" assumed "FOO";
$a = \FOO// fatal error, undefined namespace constant FOO
$a Bar\FOO// fatal error, undefined namespace constant bar\Bar\FOO
$a = \Bar\FOO// fatal error, undefined namespace constant Bar\FOO
?>

特別な定数 NULL, TRUE, FALSE, ZEND_THREAD_SAFE そして ZEND_DEBUG_BUILD は上書きできない

名前空間内で特別な組み込み定数を定義しようとすると、致命的なエラーが発生します。

例11 未定義の定数

<?php
namespace bar;
const 
NULL 0// 致命的なエラー
const true 'stupid'// これも、致命的なエラー
// etc.
?>

関連キーワード:  定数, 名前, クラス, 修飾, 関数, 解決, 定義, 解釈, 方法, 発生