The most obvious purpose of namespaces is to solve the problem of duplicate names. PHP does not allow two functions or classes to have the same name; otherwise, a fatal error will occur. In this case, the problem can be solved by simply avoiding duplicate names, and one of the most common approaches is to agree on a prefix.
Example: The project has two modules: article and message board, and each has a Comment class that handles user messages. Later, I might want to add some statistics functionality for all user messages, such as getting the total number of messages. At this point, it would be a good approach to call the methods provided by their Comment classes, but introducing both Comment classes at the same time is obviously not acceptable—the code will error out. Rewriting either Comment elsewhere would also reduce maintainability. In this case, the only option is to refactor the class names. I agreed on a naming rule: prepend the module name to the class name, like this: Article_Comment, MessageBoard_Comment.
As you can see, the names become very long, which means more code will be written when using Comment later (at least more characters). Moreover, if more integration features are added to the modules in the future, or if the modules call each other, names will need to be refactored whenever duplicates occur. Of course, noticing this problem at the start of the project and specifying naming rules can effectively avoid it. Another solution is to consider using namespaces.
Note:Constants mentioned in this article: Starting with PHP 5.3, the const keyword can be used outside of classes. Both const and define are used to declare constants (their differences are not detailed here), but in a namespace, define has a global scope, while const applies to the current space. The constants I mention in this article refer to constants declared using const.
Basics
Namespaces divide code into different spaces (regions). The names of constants, functions, and classes (to be lazy, I will refer to them as "elements" below) in each space do not affect each other. This is somewhat similar to the concept of "encapsulation" that we often mention.
To create a namespace, you need to use the namespace keyword, like this:
<?php //创建一个名为'Article'的命名空间 namespace Article; ?>
Note that there cannot be any code before the first namespace in the current script file. The following usages are all incorrect:
Example 1
//在脚本前面写了一些逻辑代码
<?php
$path = "/";
class Comment { }
namespace Article;
?>
Example 2
</html> <?php namespace Article; ?>
Why mention the first namespace? Because multiple namespaces can be created in the same script file.
Below I created two namespaces and, incidentally, added a Comment class element to each space:
<?php
//创建一个名为'Article'的命名空间
namespace Article;
//此Comment属于Article空间的元素
class Comment { }
//创建一个名为'MessageBoard'的命名空间
namespace MessageBoard;
//此Comment属于MessageBoard空间的元素
class Comment { }
?>
Elements in different spaces cannot be called directly from one another; the namespace syntax must be used:
<?php
namespace Article;
class Comment { }
namespace MessageBoard;
class Comment { }
//调用当前空间(MessageBoard)的Comment类
$comment = new Comment();
//调用Article空间的Comment类
$article_comment = new \Article\Comment();
?>
As you can see, when calling the Comment class in the article space from the MessageBoard space, a file-path-like syntax is used:\namespace name\element name
Besides classes, the usage is the same for functions and constants. Below I created new elements for the two spaces and output their values in the MessageBoard space.
<?php
namespace Article;
const PATH = '/article';
function getCommentTotal() {
return 100;
}
class Comment { }
namespace MessageBoard;
const PATH = '/message_board';
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();
?>
And indeed, I got the element data from the Article space.
Sub-namespaces
It makes sense that the namespace calling syntax is like a file path; it allows us to define sub-namespaces to describe the relationships between various spaces.
Sorry, I forgot to mention that the article and message board modules are actually both within the same blog project. If we use namespaces to express their relationship, it looks like this:
<?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();
?>
Moreover, sub-namespaces can be defined to many levels, for example:Blog\Article\Archives\Date
Global space
I have a common_inc.php script file with some useful functions and classes in it:
<?php
function getIP() { }
class FilterXSS { }
?>
If this script is included within a namespace, the elements in the script will not belong to that namespace. If the script does not define any other namespaces, its elements will always remain in the global space:
<?php namespace Blog\Article; //引入脚本文件 include './common_inc.php'; $filter_XSS = new FilterXSS(); //出现致命错误:找不到Blog\Article\FilterXSS类 $filter_XSS = new \FilterXSS(); //正确 ?>
To call elements in the global space, simply add \ before the element name; otherwise, the PHP parser will think you want to call an element in the current space. In addition to custom elements, PHP's built-in elements also belong to the global space.
It is worth mentioning that, in fact, functions and constants in the global space do not need the backslash added\and can still be called normally (I do not understand why PHP does this), but in order to correctly distinguish elements, it is still recommended to add it when calling functions.\
Name terminology
Before discussing aliases and imports, you need to know the terminology of the three types of names regarding spaces, and how PHP resolves them. The official documentation explains this very well, so I will use it directly.
- 1. Unqualified names, or class names without a prefix, for example $comment = new Comment();. If the current namespace is Blog\Article, Comment will be resolved as Blog\Article\Comment. If the code using Comment is not contained in any namespace (in the global space), then Comment will be resolved as Comment.
- 2. Qualified names, or names with a prefix, for example $comment = new Article\Comment();. If the current namespace is Blog, then Comment will be resolved as Blog\Article\Comment. If the code using Comment is not contained in any namespace (in the global space), then Comment will be resolved as Comment.
- 3. Fully qualified names, or names that include the global prefix operator, for example $comment = new \Article\Comment();. In this case, Comment is always resolved as the literal name in the code, Article\Comment.
In fact, you can compare these three types of names to a file name (e.g., comment.php), a relative path name (e.g., ./article/comment.php), and an absolute path name (e.g., /blog/article/comment.php), which may make them easier to understand.
I used several examples to illustrate them:
<?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 { }
?>
In fact, I have been using unqualified names and fully qualified names all along; now they can finally be called by their proper names.
Aliases and imports
Aliases and imports can be seen as a shortcut for calling namespace elements. PHP does not support importing functions or constants.
Both are implemented through the use operator:
<?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();
?>
I noticed—what would happen if, when importing an element, the current space has an element with the same name? Obviously, the result would be a fatal error.
<?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发生冲突,程序产生致命错误
?>
Dynamic invocation
PHP provides the namespace keyword and the __NAMESPACE__ magic constant for dynamically accessing elements. __NAMESPACE__ can be used for dynamic access by combining strings:
<?php
namespace Blog\Article;
const PATH = '/Blog/article';
class Comment { }
//namespace关键字表示当前空间
echo namespace\PATH; ///Blog/article
$comment = new namespace\Comment();
//魔法常量__NAMESPACE__的值是当前空间名称
echo __NAMESPACE__; //Blog\Article
//可以组合成字符串并调用
$comment_class_name = __NAMESPACE__ . '\Comment';
$comment = new $comment_class_name();
?>
Issues with string-form invocation
In the dynamic invocation example above, we saw a string-form dynamic calling approach. If you want to use this approach, there are two issues to note.
1. When using double quotes, special characters may be escaped.
<?php
namespace Blog\Article;
class name { }
//我是想调用Blog\Article\name
$class_name = __NAMESPACE__ . "\name"; //但是\n将被转义为换行符
$name = new $class_name(); //发生致命错误
?>
2. It will not be considered a qualified name.
PHP determines the space where an element resides, as well as the import situation, when compiling the script. However, when parsing the script, string-form calls can only be considered unqualified names or fully qualified names, and can never be qualified names.
<?php
namespace Blog;
//导入Common类
use Blog\Article\Common;
//我想使用非限定名称调用Blog\Article\Common
$common_class_name = 'Common';
//实际会被当作非限定名称,也就表示当前空间的Common类,但我当前类没有创建Common类
$common = new $common_class_name(); //发生致命错误:Common类不存在
//我想使用限定名称调用Blog\Article\Common
$common_class_name = 'Article\Common';
//实际会被当作完全限定名称,也就表示Article空间下的Common类,但我下面只定义了Blog\Article空间而不是Article空间
$common = new $common_class_name(); //发生致命错误:Article\Common类不存在
namespace Blog\Article;
class Common { }
?>
Summary
I have just started learning about PHP namespaces, so I cannot casually offer unverified advice. Personally, I think namespaces are very powerful in both role and functionality; when writing plugins or general-purpose libraries, you no longer need to worry about duplicate names. However, if a project has progressed to a certain point and you need to solve duplicate-name problems by adding namespaces, I think the workload will not be less than refactoring names. I also have to admit that its syntax adds a certain amount of complexity to a project, so it should be well planned from the very beginning, and a naming convention should be established.
Original URL: https://www.cnblogs.com/kuyuecs/p/3556421.html