PHP 名前空間
PHP 名前空間 (名前空間)
PHP 名前空間 (名前空間) は PHP 5.3 で追加されました。C# と Java を?qū)W習(xí)したことがある方にとって、名前空間は新しいものではありません。 ただし、PHP では依然として非常に重要な意味を持っています。
PHP 名前空間は、次の 2 種類の問題を解決できます:
1. ユーザーが作成したコードと、PHP の內(nèi)部クラス/関數(shù)/定數(shù)またはサードパーティのクラス/関數(shù)/定數(shù)の間の名前の競合。
2. ソース コードの可読性を向上させるために、非常に長い識(shí)別子名 (通常は最初の種類の問題を軽減するために定義される) のエイリアス (または短い) 名を作成します。
名前空間を定義する
デフォルトでは、PHP が名前空間をサポートする前と同様に、すべての定數(shù)、クラス、関數(shù)名はグローバル空間に配置されます。
名前空間はキーワード namespace で宣言されます。ファイルに名前空間が含まれている場合は、他のすべてのコードの前に名前空間を宣言する必要があります。構(gòu)文形式は次のとおりです。
< ?php // 定義代碼在 'MyProject' 命名空間中 namespace MyProject; // ... 代碼 ...
次のように、同じファイル內(nèi)で異なる名前空間コードを定義することもできます。
< ?php namespace MyProject1; // MyProject1 命名空間中的PHP代碼 namespace MyProject2; // MyProject2 命名空間中的PHP代碼 // 另一種語法 namespace MyProject3 { // MyProject3 命名空間中的PHP代碼 } ?>
名前空間を宣言する前の唯一の有効なコードは、ソース ファイルのエンコーディングを定義するために使用される宣言ステートメントです??瞻驻蚝啶工伽皮畏?PHP コードは、名前空間宣言の前に現(xiàn)れてはなりません。
<?php declare(encoding='UTF-8'); //定義多個(gè)命名空間和不包含在命名空間中的代碼 namespace MyProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } namespace { // 全局代碼 session_start(); $a = MyProject\connect(); echo MyProject\Connection::start(); } ?>
次のコードは構(gòu)文エラーを引き起こします:
<html> <?php namespace MyProject; // 命名空間前出現(xiàn)了“<html>” 會(huì)致命錯(cuò)誤 - 命名空間必須是程序腳本的第一條語句 ?>
サブネームスペース
ディレクトリやファイルとの関係と同様に、PHP ネームスペースでも階層ネームスペース名を指定できます。したがって、名前空間名は階層的な方法で定義できます。
<?php namespace MyProject\Sub\Level; //聲明分層次的單個(gè)命名空間 const CONNECT_OK = 1; class Connection { /* ... */ } function Connect() { /* ... */ } ?>
上の例では、定數(shù) MyProjectSubLevelCONNECT_OK、クラス MyProjectSubLevelConnection、および関數(shù) MyProjectSubLevelConnect を作成します。
名前空間の使用法
PHP 名前空間のクラス名は、次の 3 つの方法で參照できます:
1 など、プレフィックスのないクラス名。 =new foo(); または foo::staticmethod();現(xiàn)在の名前空間が currentnamespace の場合、foo は currentnamespacefoo に解決されます。 foo を使用するコードがグローバルであり、どの名前空間にもコードが含まれていない場合、foo は foo として解決されます。 警告: ネームスペース內(nèi)の関數(shù)または定數(shù)が未定義の場合、修飾されていない関數(shù)または定數(shù)名はグローバル関數(shù)または定數(shù)名に解決されます。
2. 修飾名、またはプレフィックスを含む名前 ($a = new subnamespacefoo() または subnamespacefoo::staticmethod(); など)?,F(xiàn)在の名前空間が currentnamespace の場合、foo は currentnamespacesubnamespacefoo に解決されます。 foo を使用するコードがグローバルであり、コードがどの名前空間にも含まれていない場合、foo はサブ名前空間 foo に解決されます。
3. 完全修飾名、またはグローバル接頭辭演算子を含む名前 ($a = new currentnamespacefoo(); または currentnamespacefoo::staticmethod(); など)。この場合、foo はコード內(nèi)で常にリテラル名 currentnamespacefoo に解決されます。
以下はこれら 3 つのメソッドの使用例です:
file1.php ファイル コード
<?php namespace Foo\Bar\subnamespace; const FOO = 1; function foo() {} class foo { static function staticmethod() {} } ?>
file2.php ファイル コード
<?php namespace Foo\Bar; include 'file1.php'; const FOO = 2; function foo() {} class foo { static function staticmethod() {} } /* 非限定名稱 */ foo(); // 解析為 Foo\Bar\foo resolves to function Foo\Bar\foo foo::staticmethod(); // 解析為類 Foo\Bar\foo的靜態(tài)方法staticmethod。resolves to class Foo\Bar\foo, method staticmethod echo FOO; // resolves to constant Foo\Bar\FOO /* 限定名稱 */ subnamespace\foo(); // 解析為函數(shù) Foo\Bar\subnamespace\foo subnamespace\foo::staticmethod(); // 解析為類 Foo\Bar\subnamespace\foo, // 以及類的方法 staticmethod echo subnamespace\FOO; // 解析為常量 Foo\Bar\subnamespace\FOO /* 完全限定名稱 */ \Foo\Bar\foo(); // 解析為函數(shù) Foo\Bar\foo \Foo\Bar\foo::staticmethod(); // 解析為類 Foo\Bar\foo, 以及類的方法 staticmethod echo \Foo\Bar\FOO; // 解析為常量 Foo\Bar\FOO ?>
グローバル クラス、関數(shù)、または定數(shù)へのアクセスには完全修飾名を使用できることに注意してください。 strlen()、例外、INI_ALL など。
名前空間內(nèi)のグローバル クラス、関數(shù)、定數(shù)にアクセスする:
<?php namespace Foo; function strlen() {} const INI_ALL = 3; class Exception {} $a = \strlen('hi'); // 調(diào)用全局函數(shù)strlen $b = \INI_ALL; // 訪問全局常量 INI_ALL $c = new \Exception('error'); // 實(shí)例化全局類 Exception ?>
名前空間と動(dòng)的言語機(jī)能
PHP の名前空間の実裝は、言語自體の動(dòng)的機(jī)能の影響を受けます。したがって、以下のコードを名前空間に変換する場合は、要素に動(dòng)的にアクセスします。
example1.php ファイルコード:
<?php class classname { function __construct() { echo __METHOD__,"\n"; } } function funcname() { echo __FUNCTION__,"\n"; } const constname = "global"; $a = 'classname'; $obj = new $a; // prints classname::__construct $b = 'funcname'; $b(); // prints funcname echo constant('constname'), "\n"; // prints global ?>
完全修飾名 (名前空間プレフィックスを含むクラス名) を使用する必要があります。動(dòng)的クラス名、関數(shù)名、または定數(shù)名では修飾名と完全修飾名に違いがないため、先頭のバックスラッシュは不要であることに注意してください。
名前空間の要素への動(dòng)的アクセス
<?php namespace namespacename; class classname { function __construct() { echo __METHOD__,"\n"; } } function funcname() { echo __FUNCTION__,"\n"; } const constname = "namespaced"; include 'example1.php'; $a = 'classname'; $obj = new $a; // prints classname::__construct $b = 'funcname'; $b(); // prints funcname echo constant('constname'), "\n"; // prints global /* note that if using double quotes, "\namespacename\classname" must be used */ $a = '\namespacename\classname'; $obj = new $a; // prints namespacename\classname::__construct $a = 'namespacename\classname'; $obj = new $a; // also prints namespacename\classname::__construct $b = 'namespacename\funcname'; $b(); // prints namespacename\funcname $b = '\namespacename\funcname'; $b(); // also prints namespacename\funcname echo constant('\namespacename\constname'), "\n"; // prints namespaced echo constant('namespacename\constname'), "\n"; // also prints namespaced ?>
名前空間キーワードと__NAMESPACE__定數(shù)
PHPは、現(xiàn)在の名前空間內(nèi)の要素にアクセスする2つの抽象メソッド、__NAMESPACE__マジック定數(shù)と名前空間キーワードをサポートしています。
定數(shù) __NAMESPACE__ の値は、現(xiàn)在の名前空間の名前を含む文字列です。どの名前空間にも含まれていないグローバル コードには、空の文字列が含まれます。
__NAMESPACE__ の例、名前空間內(nèi)のコード
<?php namespace MyProject; echo '"', __NAMESPACE__, '"'; // 輸出 "MyProject" ?>
__NAMESPACE__ の例、グローバル コード
<?php echo '"', __NAMESPACE__, '"'; // 輸出 "" ?>
定數(shù) __NAMESPACE__ は、名前を動(dòng)的に作成する場合に役立ちます。例:
名前を動(dòng)的に作成するには __NAMESPACE__ を使用します
<?php namespace MyProject; function get($classname) { $a = __NAMESPACE__ . '\' . $classname; return new $a; } ?>
キーワード名前空間を使用して明示的にアクセスできます現(xiàn)在の名前空間またはサブ名前空間の要素。これは、クラスの self 演算子に相當(dāng)します。
名前空間演算子、名前空間內(nèi)のコード
<?php namespace MyProject; use blah\blah as mine; // see "Using namespaces: importing/aliasing" blah\mine(); // calls function blah\blah\mine() namespace\blah\mine(); // calls function MyProject\blah\mine() namespace\func(); // calls function MyProject\func() namespace\sub\func(); // calls function MyProject\sub\func() namespace\cname::method(); // calls static method "method" of class MyProject\cname $a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname $b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b ?>
名前空間演算子、グローバルコード
<?php namespace\func(); // calls function func() namespace\sub\func(); // calls function sub\func() namespace\cname::method(); // calls static method "method" of class cname $a = new namespace\sub\cname(); // instantiates object of class sub\cname $b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b ?>
名前空間を使用: alias/import
PHP 名前空間サポートには、エイリアスまたはインポートを使用する 2 つの方法があります。クラス名、または名前空間名のエイリアス。 PHP は関數(shù)や定數(shù)のインポートをサポートしていないことに注意してください。
PHP では、エイリアスは use 演算子を使用して実裝されます。 以下に、3 つのインポート方法をすべて使用する例を示します。
1. use 演算子を使用してエイリアスをインポート/使用します
<?php namespace foo; use My\Full\Classname as Another; // 下面的例子與 use My\Full\NSname as NSname 相同 use My\Full\NSname; // 導(dǎo)入一個(gè)全局類 use \ArrayObject; $obj = new namespace\Another; // 實(shí)例化 foo\Another 對象 $obj = new Another; // 實(shí)例化 My\Full\Classname 對象 NSname\subns\func(); // 調(diào)用函數(shù) My\Full\NSname\subns\func $a = new ArrayObject(array(1)); // 實(shí)例化 ArrayObject 對象 // 如果不使用 "use \ArrayObject" ,則實(shí)例化一個(gè) foo\ArrayObject 對象 ?>
2 複數(shù)の use ステートメントを含めます。
<?php use My\Full\Classname as Another, My\Full\NSname; $obj = new Another; // 實(shí)例化 My\Full\Classname 對象 NSname\subns\func(); // 調(diào)用函數(shù) My\Full\NSname\subns\func ?>インポート操作はコンパイル中に実行されますが、動(dòng)的クラス名、関數(shù)名、または定數(shù)名は実行されません。 3. インポート名と動(dòng)的名
<?php use My\Full\Classname as Another, My\Full\NSname; $obj = new Another; // 實(shí)例化一個(gè) My\Full\Classname 對象 $a = 'Another'; $obj = new $a; // 實(shí)際化一個(gè) Another 對象 ?>さらに、インポート操作は非修飾名と修飾名にのみ影響します。完全修飾名は決定的であるため、インポートの影響を受けません。 4. インポートと完全修飾名
<?php use My\Full\Classname as Another, My\Full\NSname; $obj = new Another; // instantiates object of class My\Full\Classname $obj = new \Another; // instantiates object of class Another $obj = new Another\thing; // instantiates object of class My\Full\Classname\thing $obj = new \Another\thing; // instantiates object of class Another\thing ?>
名前空間の使用: フォールバックグローバル関數(shù)/定數(shù)
名前空間で、PHP が修飾されていないクラス、関數(shù)、または定數(shù)の名前を検出すると、別の優(yōu)先順位戦略を使用して名前を解決します。クラス名は常に現(xiàn)在の名前空間內(nèi)の名前に解決されます。したがって、システム內(nèi)のクラス名、または名前空間に含まれていないクラス名にアクセスする場合は、次のような完全修飾名を使用する必要があります。
1. 名前空間內(nèi)のグローバル クラスにアクセスする
<?php namespace A\B\C; class Exception extends \Exception {} $a = new Exception('hi'); // $a 是類 A\B\C\Exception 的一個(gè)對象 $b = new \Exception('hi'); // $b 是類 Exception 的一個(gè)對象 $c = new ArrayObject; // 致命錯(cuò)誤, 找不到 A\B\C\ArrayObject 類 ?>
現(xiàn)在の名前空間の場合、関數(shù)と定數(shù)の場合関數(shù)または定數(shù)がグローバル空間に存在しない場合、PHP はグローバル空間で関數(shù)または定數(shù)を使用するようにフォールバックします。
2. 名前空間內(nèi)のグローバル関數(shù)/定數(shù)をバックアップする
<?php namespace A\B\C; const E_ERROR = 45; function strlen($str) { return \strlen($str) - 1; } echo E_ERROR, "\n"; // 輸出 "45" echo INI_ALL, "\n"; // 輸出 "7" - 使用全局常量 INI_ALL echo strlen('hi'), "\n"; // 輸出 "1" if (is_array('hi')) { // 輸出 "is not array" echo "is array\n"; } else { echo "is not array\n"; } ?>
グローバル空間
名前空間が定義されていない場合、すべてのクラスと関數(shù)はグローバル空間で定義され、PHP では名前付けが導(dǎo)入されます。以前と同じです。名前に接頭辭を付けると、その名前が別の名前空間にある場合でも、その名前がグローバル空間にあることを示します。 グローバル空間命令の使用<?php namespace A\B\C; /* 這個(gè)函數(shù)是 A\B\C\fopen */ function fopen() { /* ... */ $f = \fopen(...); // 調(diào)用全局的fopen函數(shù) return $f; } ?>
名前空間の順序
名前空間が作成されてから、最もエラーが発生しやすいのは、クラスを使用するとき、このクラスの検索パスは何でしょうか?<?php namespace A; use B\D, C\E as F; // 函數(shù)調(diào)用 foo(); // 首先嘗試調(diào)用定義在命名空間"A"中的函數(shù)foo() // 再嘗試調(diào)用全局函數(shù) "foo" \foo(); // 調(diào)用全局空間函數(shù) "foo" my\foo(); // 調(diào)用定義在命名空間"A\my"中函數(shù) "foo" F(); // 首先嘗試調(diào)用定義在命名空間"A"中的函數(shù) "F" // 再嘗試調(diào)用全局函數(shù) "F" // 類引用 new B(); // 創(chuàng)建命名空間 "A" 中定義的類 "B" 的一個(gè)對象 // 如果未找到,則嘗試自動(dòng)裝載類 "A\B" new D(); // 使用導(dǎo)入規(guī)則,創(chuàng)建命名空間 "B" 中定義的類 "D" 的一個(gè)對象 // 如果未找到,則嘗試自動(dòng)裝載類 "B\D" new F(); // 使用導(dǎo)入規(guī)則,創(chuàng)建命名空間 "C" 中定義的類 "E" 的一個(gè)對象 // 如果未找到,則嘗試自動(dòng)裝載類 "C\E" new \B(); // 創(chuàng)建定義在全局空間中的類 "B" 的一個(gè)對象 // 如果未發(fā)現(xiàn),則嘗試自動(dòng)裝載類 "B" new \D(); // 創(chuàng)建定義在全局空間中的類 "D" 的一個(gè)對象 // 如果未發(fā)現(xiàn),則嘗試自動(dòng)裝載類 "D" new \F(); // 創(chuàng)建定義在全局空間中的類 "F" 的一個(gè)對象 // 如果未發(fā)現(xiàn),則嘗試自動(dòng)裝載類 "F" // 調(diào)用另一個(gè)命名空間中的靜態(tài)方法或命名空間函數(shù) B\foo(); // 調(diào)用命名空間 "A\B" 中函數(shù) "foo" B::foo(); // 調(diào)用命名空間 "A" 中定義的類 "B" 的 "foo" 方法 // 如果未找到類 "A\B" ,則嘗試自動(dòng)裝載類 "A\B" D::foo(); // 使用導(dǎo)入規(guī)則,調(diào)用命名空間 "B" 中定義的類 "D" 的 "foo" 方法 // 如果類 "B\D" 未找到,則嘗試自動(dòng)裝載類 "B\D" \B\foo(); // 調(diào)用命名空間 "B" 中的函數(shù) "foo" \B::foo(); // 調(diào)用全局空間中的類 "B" 的 "foo" 方法 // 如果類 "B" 未找到,則嘗試自動(dòng)裝載類 "B" // 當(dāng)前命名空間中的靜態(tài)方法或函數(shù) A\B::foo(); // 調(diào)用命名空間 "A\A" 中定義的類 "B" 的 "foo" 方法 // 如果類 "A\A\B" 未找到,則嘗試自動(dòng)裝載類 "A\A\B" \A\B::foo(); // 調(diào)用命名空間 "A\B" 中定義的類 "B" 的 "foo" 方法 // 如果類 "A\B" 未找到,則嘗試自動(dòng)裝載類 "A\B" ?>名前解決は次のルールに従います: 1. 完全修飾名を持つ関數(shù)、クラス、および定數(shù)の呼び出しはコンパイル時(shí)に解決されます。たとえば、新しい AB はクラス AB に解決されます。 2. すべての非修飾名と修飾名 (非完全修飾名) は、現(xiàn)在のインポート ルールに従ってコンパイル時(shí)に変換されます。たとえば、名前空間 ABC が C としてインポートされた場合、CDe() の呼び出しは ABCDe() に変換されます。 3. 名前空間內(nèi)では、インポート ルールに従って変換されないすべての修飾名の前に現(xiàn)在の名前空間名が付きます。たとえば、CDe() が名前空間 AB 內(nèi)で呼び出された場合、CDe() は ABCDe() に変換されます。 4. 修飾されていないクラス名は、現(xiàn)在のインポート規(guī)則に従ってコンパイル時(shí)に変換されます (短いインポート名の代わりに完全な名前が使用されます)。たとえば、名前空間 ABC が C としてインポートされる場合、 new C() は new ABC() に変換されます。 5. 名前空間 (例: AB) 內(nèi)では、非修飾名への関數(shù)呼び出しは実行時(shí)に解決されます。たとえば、関數(shù) foo() の呼び出しは次のように解析されます: 1. 現(xiàn)在の名前空間で ABfoo() という名前の関數(shù)を見つけます 2. グローバル空間で関數(shù) foo() を見つけて呼び出してみます。 6. 名前空間 (AB など) 內(nèi)の非修飾名または修飾名クラス (非完全修飾名) への呼び出しは実行時(shí)に解決されます。以下は、new C() と new DE() を呼び出す解析プロセスです: new C() の解析:
1. 現(xiàn)在の名前空間で ABC クラスを見つけます。
2. クラス ABC を自動(dòng)ロードしてみます。
new DE() の分析:
3. クラス名の前に現(xiàn)在の名前空間名を追加して ABDE となり、クラスを検索します。
4. クラス ABDE を自動(dòng)ロードしてみます。
グローバル名前空間內(nèi)のグローバル クラスを參照するには、完全修飾名 new C() を使用する必要があります。