クロージャ[表示]を探索した後、再度名前空間を探索してみましょう。
名前空間については、公式ドキュメントですでに詳細に説明されています[表示]。ここでいくつかの練習と要約を行いました。
名前空間の最も明確な目的の 1 つは、名前の重複問題 を解決することです。PHP では、2 つの関数またはクラスが同じ名前を持つことは許可されません。そうしないと、致命的なエラーが発生します。この場合、名前の重複を避ける限り解決できます。最も一般的な方法は、プレフィックスを合意することです。
例: プロジェクトには、article と message board という 2 つのモジュールがあり、それぞれにユーザー メッセージを処理するためのクラス Comment があります。 将来的には、すべてのユーザー メッセージの情報統計関数を追加する可能性があります。たとえば、すべてのメッセージの数を取得したいと考えています。現時点では、それらが提供するメソッド Comment を呼び出すことは良い考えですが、同時に独自の Comment クラスを導入することは明らかに不可能であり、コードが間違ってしまい、Comment を書き換えてしまいます。 を別の場所に置くと保守性も低下します。次に、クラス名をリファクタリングするだけで、次のようにクラス名の前にモジュール名を追加するという命名規則に同意しました。
ご覧のとおり、名前が非常に長くなりました。これは、将来 Comment を使用するときに、より多くのコード (少なくともより多くの文字) が記述されることを意味します。さらに、将来的に各モジュールに統合関数を追加したり、相互に呼び出したりする場合は、名前が重複した場合に名前を再構築する必要があります。もちろん、プロジェクトの開始時にこの問題に気づき、名前付けルールを指定することで、この問題は回避できます。別の解決策は、名前空間を使用することです。
注:
この記事で説明されている定数: PHP 5.3 以降、
constキーワードをクラスの外で使用できるようになりました。 const と
defineはどちらも定数を宣言するために使用されます (その違いについては詳しく説明しません) が、名前空間では、define がグローバルに動作するのに対し、const は現在の空間に対して動作します。記事内で言及する定数は、constを使用して宣言された定数を指します。 基本
名前空間は、コードを異なる空間(領域)に分割します。各空間の定数、関数、クラスの名前(面倒なので、以下では要素
と呼びます)は、互いに影響を与えません。これは、何かに似ています。私たちはよく「カプセル化」という概念について言及します。名前空間を作成するには、次のように
リーリー
現在のスクリプト ファイルの最初の名前空間の前にコードを置くことはできないことに注意してください。次の記述方法は間違っています:
リーリー
最初の名前空間について言及する必要があるのはなぜですか?同じスクリプト ファイル内に複数の名前空間を作成できるためです。 以下では 2 つの名前空間を作成し、これら 2 つの空間のそれぞれに Comment クラス要素を追加しました。 リーリー
異なる空間間で他の要素を直接呼び出すことはできません。名前空間構文を使用する必要があります: リーリー
MessageBoardスペースのarticleスペースのCommentクラスを呼び出すときに、ファイルパスのような構文が使用されることがわかります: スペース名要素名
クラスを除き、関数と定数の使い方は同じです。以下では、2つのスペースに新しい要素を作成し、その値をMessageBoardスペースに出力します。 リーリー
然后我的确得到了Article空间的元素数据。 命名空间的调用语法像文件路径一样是有道理的,它允许我们自定义子空间来描述各个空间之间的关系。 抱歉我忘了说,article和message board这两个模块其实都是处于同一个blog项目内。如果用命名空间来表达它们的关系,是这样: 而且,子空间还可以定义很多层次,比如说 Blog\Article\Archives\Date 我有一个common_inc.php脚本文件,里面有一些好用的函数和类: 在一个命名空间里引入这个脚本,脚本里的元素不会归属到这个命名空间。如果这个脚本里没有定义其它命名空间,它的元素就始终处于公共空间中: 调用公共空间的方式是直接在元素名称前加 \ 就可以了,否则PHP解析器会认为我想调用当前空间下的元素。除了自定义的元素,还包括PHP自带的元素,都属于公共空间。 要提一下,其实公共空间的函数和常量不用加 \ 也可以正常调用(不明白PHP为什么要这样做),但是为了正确区分元素,还是建议调用函数的时候加上 \ 在说别名和导入之前,需要知道关于空间三种名称的术语,以及PHP是怎样解析它们的。官方文档说得非常好,我就直接拿来套了。 其实可以把这三种名称类比为文件名(例如 comment.php)、相对路径名(例如 ./article/comment.php)、绝对路径名(例如 /blog/article/comment.php),这样可能会更容易理解。 我用了几个示例来表示它们: 其实之前我就一直在使用非限定名称和完全限定名称,现在它们终于可以叫出它们的名称了。 别名和导入可以看作是调用命名空间元素的一种快捷方式。PHP并不支持导入函数或常量。 它们都是通过使用use操作符来实现: 我注意到,如果导入元素的时候,当前空间有相同的名字元素将会怎样?显然结果会发生致命错误。 例: PHP提供了namespace关键字和__NAMESPACE__魔法常量动态的访问元素,__NAMESPACE__可以通过组合字符串的形式来动态访问: 上面的动态调用的例子中,我们看到了字符串形式的动态调用方式,如果要使用这种方式要注意两个问题。 1. 使用双引号的时候特殊字符可能被转义 2. 不会认为是限定名称 PHP在编译脚本的时候就确定了元素所在的空间,以及导入的情况。而在解析脚本时字符串形式调用只能认为是非限定名称和完全限定名称,而永远不可能是限定名称。 我对PHP的命名空间刚刚接触,也不能随便给一些没有实践的建议。我个人认为命名空间的作用和功能都很强大,如果要写插件或者通用库的时候再也不用担心重名问题。不过如果项目进行到一定程度,要通过增加命名空间去解决重名问题,我觉得工作量不会比重构名字少。也不得不承认它的语法会对项目增加一定的复杂度,因此从项目一开始的时候就应该很好的规划它,并制定一个命名规范。 子空间
<?<span>php
</span><span>//</span><span>我用这样的命名空间表示处于blog下的article模块</span>
<span>namespace Blog\Article;
</span><span>class</span><span> Comment { }
</span><span>//</span><span>我用这样的命名空间表示处于blog下的message board模块</span>
<span>namespace Blog\MessageBoard;
</span><span>class</span><span> Comment { }
</span><span>//</span><span>调用当前空间的类</span>
<span>$comment</span> = <span>new</span><span> Comment();
</span><span>//</span><span>调用Blog\Article空间的类</span>
<span>$article_comment</span> = <span>new</span><span> \Blog\Article\Comment();
</span>?>
公共空间
<?<span>php
</span><span>function</span><span> getIP() { }
</span><span>class</span><span> FilterXSS { }
</span>?>
<?<span>php
namespace Blog\Article;
</span><span>//</span><span>引入脚本文件</span>
<span>include</span> './common_inc.php'<span>;
</span><span>$filter_XSS</span> = <span>new</span> FilterXSS(); <span>//</span><span>出现致命错误:找不到Blog\Article\FilterXSS类</span>
<span>$filter_XSS</span> = <span>new</span> \FilterXSS(); <span>//</span><span>正确</span>
?>
名称术语
<?<span>php
</span><span>//</span><span>创建空间Blog</span>
<span>namespace Blog;
</span><span>class</span><span> Comment { }
</span><span>//</span><span>非限定名称,表示当前Blog空间
//这个调用将被解析成 Blog\Comment();</span>
<span>$blog_comment</span> = <span>new</span><span> Comment();
</span><span>//</span><span>限定名称,表示相对于Blog空间
//这个调用将被解析成 Blog\Article\Comment();</span>
<span>$article_comment</span> = <span>new</span> Article\Comment(); <span>//类</span><span>前面没有反斜杆\
//完全限定名称,表示绝对于Blog空间
//这个调用将被解析成 Blog\Comment();</span>
<span>$article_comment</span> = <span>new</span> \Blog\Comment(); <span>//类</span><span>前面有反斜杆\
//完全限定名称,表示绝对于Blog空间
//这个调用将被解析成 Blog\Article\Comment();</span>
<span>$article_comment</span> = <span>new</span> \Blog\Article\Comment(); <span>//类</span><span>前面有反斜杆\
//创建Blog的子空间Article</span>
<span>namespace Blog\Article;
</span><span>class</span><span> Comment { }
</span>?>
别名和导入
<?<span>php
namespace Blog\Article;
</span><span>class</span><span> Comment { }
</span><span>//创建一个BBS空间(我有打算开个论坛)</span>
<span>namespace BBS;
</span><span>//</span><span>导入一个命名空间</span>
<span>use</span><span> Blog\Article;
</span><span>//</span><span>导入命名空间后可使用限定名称调用元素</span>
<span>$article_comment</span> = <span>new</span><span> Article\Comment();
</span><span>//</span><span>为命名空间使用别名</span>
<span>use</span> Blog\Article <span>as</span><span> Arte;
</span><span>//</span><span>使用别名代替空间名</span>
<span>$article_comment</span> = <span>new</span><span> Arte\Comment();
</span><span>//</span><span>导入一个类</span>
<span>use</span><span> Blog\Article\Comment;
</span><span>//</span><span>导入类后可使用非限定名称调用元素</span>
<span>$article_comment</span> = <span>new</span><span> Comment();
</span><span>//</span><span>为类使用别名</span>
<span>use</span> Blog\Article\Comment <span>as</span><span> Comt;
</span><span>//</span><span>使用别名代替空间名</span>
<span>$article_comment</span> = <span>new</span><span> Comt();
</span>?>
<?<span>php
namespace Blog\Article;
</span><span>class</span><span> Comment { }
namespace BBS;
</span><span>class</span><span> Comment { }
</span><span>Class</span><span> Comt { }
</span><span>//</span><span>导入一个类</span>
<span>use</span><span> Blog\Article\Comment;
</span><span>$article_comment</span> = <span>new</span> Comment(); <span>//</span><span>与当前空间的Comment发生冲突,程序产生致命错误
//为类使用别名</span>
<span>use</span> Blog\Article\Comment <span>as</span><span> Comt;
</span><span>$article_comment</span> = <span>new</span> Comt(); <span>//</span><span>与当前空间的Comt发生冲突,程序产生致命错误</span>
?>
动态调用
<?<span>php
namespace Blog\Article;
</span><span>const</span> PATH = '/Blog/article'<span>;
</span><span>class</span><span> Comment { }
</span><span>//</span><span>namespace关键字表示当前空间</span>
<span>echo</span> namespace\PATH; <span>//</span><span>/Blog/article</span>
<span>$comment</span> = <span>new</span><span> namespace\Comment();
</span><span>//</span><span>魔法常量__NAMESPACE__的值是当前空间名称</span>
<span>echo</span> __NAMESPACE__; <span>//</span><span>Blog\Article
//可以组合成字符串并调用</span>
<span>$comment_class_name</span> = __NAMESPACE__ . '\Comment'<span>;
</span><span>$comment</span> = <span>new</span> <span>$comment_class_name</span><span>();
</span>?>
字符串形式调用问题
<?<span>php
namespace Blog\Article;
</span><span>class</span><span> name { }
</span><span>//</span><span>我是想调用Blog\Article\name</span>
<span>$class_name</span> = __NAMESPACE__ . "\name"; <span>//</span><span>但是\n将被转义为换行符</span>
<span>$name</span> = <span>new</span> <span>$class_name</span>(); <span>//</span><span>发生致命错误</span>
?>
<?<span>php
namespace Blog;
</span><span>//</span><span>导入Common类</span>
<span>use</span><span> Blog\Article\Common;
</span><span>//</span><span>我想使用非限定名称调用Blog\Article\Common</span>
<span>$common_class_name</span> = 'Common'<span>;
</span><span>//</span><span>实际会被当作非限定名称,也就表示当前空间的Common类,但我当前类没有创建Common类</span>
<span>$common</span> = <span>new</span> <span>$common_class_name</span>(); <span>//</span><span>发生致命错误:Common类不存在
//我想使用限定名称调用Blog\Article\Common</span>
<span>$common_class_name</span> = 'Article\Common'<span>;
</span><span>//</span><span>实际会被当作完全限定名称,也就表示Article空间下的Common类,但我下面只定义了Blog\Article空间而不是Article空间</span>
<span>$common</span> = <span>new</span> <span>$common_class_name</span>(); <span>//</span><span>发生致命错误:Article\Common类不存在</span>
<span>
namespace Blog\Article;
</span><span>class</span><span> Common { }
</span>?>
总结