ホームページ  >  記事  >  バックエンド開発  >  PHP - 名前空間の使用法の詳細な紹介

PHP - 名前空間の使用法の詳細な紹介

王林
王林転載
2019-08-28 16:01:422147ブラウズ

名前空間については公式ドキュメント [View] で既に詳しく解説されているので、ここで練習とまとめをしておきます。

名前空間の最も明確な目的の 1 つは、名前の重複の問題を解決することです。PHP では、2 つの関数またはクラスが同じ名前を持つことは許可されていません。そうしないと、致命的なエラーが発生します。この場合、名前の重複を避ければ解決できますが、最も一般的な方法はプレフィックスを合意することです。

例: プロジェクトには、記事とメッセージ ボードという 2 つのモジュールがあり、それぞれにユーザー メッセージを処理するためのクラス Comment があります。後で、すべてのユーザー メッセージの情報統計関数を追加する場合があります (たとえば、すべてのメッセージの数を取得したいなど)。現時点では、Comment によって提供されるメソッドを呼び出すことは良い考えですが、それぞれの Comment クラスを同時に導入することは明らかに不可能です。コードではエラーが発生し、Comment を別の場所に書き換えるとエラーも発生します。メンテナンス性が低下します。この時点ではクラス名を再構築することしかできないので、命名規則に同意し、Article_Comment、MessageBoard_Comment

のようにクラス名の前にモジュール名を追加しました。ご覧のとおり、名前は次のようになります。非常に長いです。これは、将来コメントを使用するときに、より多くのコード (少なくともより多くの文字) を記述することを意味します。さらに、将来的に各モジュールに統合関数を追加したり、相互に呼び出したりする場合は、名前が重複した場合に名前を再構築する必要があります。もちろん、プロジェクトの開始時にこの問題に気づき、名前付けルールを指定することで、この問題は回避できます。別の解決策は、名前空間を使用することです。

注:

この記事で説明されている定数: PHP5.3 以降、const キーワードはクラスの外で使用できるようになりました。 const と define はどちらも定数の宣言に使用されます (その違いについては詳しく説明しません) が、名前空間では、define はグローバルに機能するのに対し、const は現在の空間に対して機能します。記事内で言及した定数は、const を使用して宣言された定数を指します。

基本:

名前空間は、コードをさまざまな空間 (領域) に分割し、各空間の定数、関数、クラスを分割します (目的)これは、よく言われる「カプセル化」の概念と似ています。

名前空間を作成するには、名前空間キーワードを使用する必要があります。

コードは次のとおりです。

<?php 
//创建一个名为&#39;Article&#39;的命名空间
namespace Article;
?>

の前にコードを置くことはできないことに注意してください。現在のスクリプト ファイルの最初の名前空間の場合、次の記述方法はすべて間違っています:

コードは次のとおりです:

//在脚本前面写了一些逻辑代码
<?php
$path = "/";
class Comment { }
namespace Article;
?>

または次のとおりです:

//在脚本前面输出了一些字符
<html></html>
<?php
namespace Article;
?>

最初の名前空間を言う必要があるのはなぜですか? ?同じスクリプト ファイル内に複数の名前空間を作成できるためです。

以下では、2 つの名前空間を作成し、これら 2 つの空間のそれぞれに Comment クラス要素を追加しました。

コードは次のとおりです。

<?php 
//创建一个名为&#39;Article&#39;的命名空间
namespace Article;
//此Comment属于Article空间的元素
class Comment { }

//创建一个名为&#39;MessageBoard&#39;的命名空间
namespace MessageBoard;
//此Comment属于MessageBoard空间的元素
class Comment { }
?>

異なるスペース間を直接接続することはできません。他の要素を呼び出すには、名前空間構文を使用する必要があります:

コードは次のとおりです:

<?php 
namespace Article;
class Comment { }

namespace MessageBoard;
class Comment { }
//调用当前空间(MessageBoard)的Comment类
$comment = new Comment();
//调用Article空间的Comment类
$article_comment = new \Article\Comment();
?>

ご覧のとおり、メッセージボード スペースの記事スペースで Comment クラスを呼び出すとき、 a ファイルパスのような構文: \スペース名\要素名

クラスを除き、関数と定数の使い方は同じです。以下では、2つのスペースに新しい要素を作成し、メッセージボードスペースに配置します。それらの値は に出力されます。

コードは次のとおりです:

<?php 
namespace Article;
const PATH = &#39;/article&#39;;
function getCommentTotal() {
    return 100;
}
class Comment { }

namespace MessageBoard;
const PATH = &#39;/message_board&#39;;
function getCommentTotal() {
    return 300;
}
class Comment { }
//调用当前空间的常量、函数和类
echo PATH; ///message_board
echo getCommentTotal(); //300
$comment = new Comment();
//调用Article空间的常量、函数和类
echo \Article\PATH; ///article
echo \Article\getCommentTotal(); //100
$article_comment = new \Article\Comment();
?>

サブスペース:

ファイル パスのような名前空間の呼び出し構文は理にかなっており、これにより次のことが可能になります。カスタマイズ サブスペースは、スペース間の関係を記述するために使用されます。

申し訳ありませんが、2 つのモジュールの記事と掲示板が実際には同じブログ プロジェクト内にあることを忘れていました。名前空間を使用してそれらの関係を表現する場合

<?php 
//我用这样的命名空间表示处于blog下的article模块
namespace Blog\Article;
class Comment { }

//我用这样的命名空间表示处于blog下的message board模块
namespace Blog\MessageBoard;
class Comment { }
//调用当前空间的类
$comment = new Comment();
//调用Blog\Article空间的类
$article_comment = new \Blog\Article\Comment();
?>

パブリックスペース:

私は common_inc.php スクリプト ファイルを持っています。これにはいくつかの便利な関数とクラスがあります。

<?php 
function getIP() { }
class FilterXSS { }
?>

このスクリプトを名前空間に導入すると、スクリプト内の要素はこの名前空間に属しません。このスクリプトで他の名前空間が定義されていない場合、その要素は常にパブリック スペースにあります:

<?php 
namespace Blog\Article;
//引入脚本文件
include &#39;./common_inc.php&#39;;
$filter_XSS = new FilterXSS(); //出现致命错误:找不到Blog\Article\FilterXSS类
$filter_XSS = new \FilterXSS(); //正确
?>

パブリック スペースを呼び出す方法は、要素名の前に \ を直接追加することです。そうしないと、PHP パーサーが次のように判断します。現在のスペースの下にある要素を呼び出したいと考えています。カスタム要素に加えて、PHP に付属する要素もありますが、これらはすべてパブリック スペースに属しています。 \ を追加します (PHP がなぜこれを行うのかわかりません) が、要素を正しく区別するために、関数を呼び出すときに \

3 と名前用語

を追加することをお勧めします。エイリアスとインポートについて話すには、スペースの 3 つの名前の用語と、PHP がそれらをどのように解析するかを知る必要があります。公式ドキュメントは非常に優れていたので、そのまま使用しました。

1.非限定名称,或不包含前缀的类名称,例如 $comment = new Comment();。如果当前命名空间是Blog\Article,Comment将被解析为Blog\Article\Comment。如果使用Comment的代码不包含在任何命名空间中的代码(全局空间中),则Comment会被解析为Comment。

2.限定名称,或包含前缀的名称,例如 $comment = new Article\Comment();。如果当前的命名空间是Blog,则Comment会被解析为Blog\Article\Comment。如果使用Comment的代码不包含在任何命名空间中的代码(全局空间中),则Comment会被解析为Comment。

3.完全限定名称,或包含了全局前缀操作符的名称,例如 $comment = new \Article\Comment();。在这种情况下,Comment总是被解析为代码中的文字名(literal name)Article\Comment。

其实可以把这三种名称类比为文件名(例如 comment.php)、相对路径名(例如 ./article/comment.php)、绝对路径名(例如 /blog/article/comment.php),这样可能会更容易理解。

我用了几个示例来表示它们:

<?php 
//创建空间Blog
namespace Blog;
class Comment { }
//非限定名称,表示当前Blog空间
//这个调用将被解析成 Blog\Comment();
$blog_comment = new Comment();
//限定名称,表示相对于Blog空间
//这个调用将被解析成 Blog\Article\Comment();
$article_comment = new Article\Comment(); //类前面没有反斜杆\
//完全限定名称,表示绝对于Blog空间
//这个调用将被解析成 Blog\Comment();
$article_comment = new \Blog\Comment(); //类前面有反斜杆\
//完全限定名称,表示绝对于Blog空间
//这个调用将被解析成 Blog\Article\Comment();
$article_comment = new \Blog\Article\Comment(); //类前面有反斜杆\

//创建Blog的子空间Article
namespace Blog\Article;
class Comment { }
?>

别名和导入
别名和导入可以看作是调用命名空间元素的一种快捷方式。PHP并不支持导入函数或常量。

它们都是通过使用use操作符来实现

代码如下:

<?php 
namespace Blog\Article;
class Comment { }

//创建一个BBS空间(我有打算开个论坛)
namespace BBS;
//导入一个命名空间
use Blog\Article;
//导入命名空间后可使用限定名称调用元素
$article_comment = new Article\Comment();
//为命名空间使用别名
use Blog\Article as Arte;
//使用别名代替空间名
$article_comment = new Arte\Comment();
//导入一个类
use Blog\Article\Comment;
//导入类后可使用非限定名称调用元素
$article_comment = new Comment();
//为类使用别名
use Blog\Article\Comment as Comt;
//使用别名代替空间名
$article_comment = new Comt();
?>

我注意到,如果导入元素的时候,当前空间有相同的名字元素将会怎样?显然结果会发生致命错误。

<?php 
namespace Blog\Article;
class Comment { }

namespace BBS;
class Comment { }
Class Comt { }

//导入一个类
use Blog\Article\Comment;
$article_comment = new Comment(); //与当前空间的Comment发生冲突,程序产生致命错误
//为类使用别名
use Blog\Article\Comment as Comt;
$article_comment = new Comt(); //与当前空间的Comt发生冲突,程序产生致命错误
?>

动态调用
PHP提供了namespace关键字和__NAMESPACE__魔法常量动态的访问元素,__NAMESPACE__可以通过组合字符串的形式来动态访问

<?php 
namespace Blog\Article;
const PATH = &#39;/Blog/article&#39;;
class Comment { }

//namespace关键字表示当前空间
echo namespace\PATH; ///Blog/article
$comment = new namespace\Comment();
//魔法常量__NAMESPACE__的值是当前空间名称
echo __NAMESPACE__; //Blog\Article
//可以组合成字符串并调用
$comment_class_name = __NAMESPACE__ . &#39;\Comment&#39;;
$comment = new $comment_class_name();
?>

字符串形式调用问题:

上面的动态调用的例子中,我们看到了字符串形式的动态调用方式,如果要使用这种方式要注意两个问题

1、使用""时特殊字符可能被转义

<?php 
namespace Blog\Article;
class name { }
//我是想调用Blog\Article\name
$class_name = __NAMESPACE__ . "\name"; //但是\n将被转义为换行符
$name = new $class_name(); //发生致命错误
?>

2、不会认为是限定名称

PHP在编译脚本的时候就确定了元素所在的空间,以及导入的情况。而在解析脚本时字符串形式调用只能认为是非限定名称和完全限定名称,而永远不可能是限定名称

<?php 
namespace Blog;
//导入Common类
use Blog\Article\Common;
//我想使用非限定名称调用Blog\Article\Common
$common_class_name = &#39;Common&#39;;
//实际会被当作非限定名称,也就表示当前空间的Common类,但我当前类没有创建Common类
$common = new $common_class_name(); //发生致命错误:Common类不存在
//我想使用限定名称调用Blog\Article\Common
$common_class_name = &#39;Article\Common&#39;;
//实际会被当作完全限定名称,也就表示Article空间下的Common类,但我下面只定义了Blog\Article空间而不是Article空间
$common = new $common_class_name(); //发生致命错误:Article\Common类不存在

namespace Blog\Article;
class Common { }
?>

总结
我对PHP的命名空间刚刚接触,也不能随便给一些没有实践的建议。我个人认为命名空间的作用和功能都很强大,如果要写插件或者通用库的时候再也不用担心重名问题。不过如果项目进行到一定程度,要通过增加命名空间去解决重名问题,我觉得工作量不会比重构名字少。也不得不承认它的语法会对项目增加一定的复杂度,因此从项目一开始的时候就应该很好的规划它,并制定一个命名规范。

更多相关问题请访问PHP中文网:PHP视频教程

以上がPHP - 名前空間の使用法の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。