On PHP Namespace

Keywords: Programming PHP less

End of closure[ see ], explore namespace again.

For namespaces, the official documentation has been detailed[ see ], I have done some practice and summary here.

One of the most explicit purposes of namespace is to solve the problem of duplicate names. Two functions or classes are not allowed to have the same name in PHP, otherwise a fatal error will occur. In this case, it can be solved as long as the naming repetition is avoided. The most common way is to contract a prefix.

For example, there are two modules in the project: article and message board, each of which has a Comment class to process user comments. After that, I may want to add some information statistics functions for all users' comments, for example, I want to get the number of all comments. It's a good practice to call the methods provided by their comments at this time, but it's obviously not good to introduce their own comments at the same time. The code will make mistakes, and overriding any Comment in another place will also reduce the maintainability. At that time, I can only reconstruct the class name. I have agreed on a naming rule, adding the module name before the class name, like this: article [Comment], messageboard [Comment]

As you can see, the name becomes very long, which means that more code (at least more characters) will be written when using Comment in the future. In addition, in the future, if you want to add more integration functions to each module, or call each other, you need to refactor the name when duplicate names occur. Of course, we should pay attention to this problem at the beginning of the project and stipulate the naming rules to avoid this problem. Another solution might consider using namespaces.

 

Note:

Constants mentioned in this article: PHP 5.3 starts with the const keyword, which can be used outside the class. Const and define are used to declare constants (their differences are not detailed), but in the namespace, define is used globally, while const is used in the current space. Constants I mentioned in this article refer to constants declared with const.

 

 

Basics

Namespace divides the code into different spaces (regions). The names of constants, functions and classes in each space (I'll call them elements in order to be lazy) don't affect each other. This is similar to the concept of "encapsulation" that we often refer to.

To create a namespace, you need to use the namespace keyword, as follows:

<?php

//Create a namespace named 'Article'
namespace Article;

?>

 

Note that the first namespace of the current script file cannot be preceded by any code, and the following writing method is wrong:

//Example 1
//Write some logic code in front of the script

<?php

$path = "/";

class Comment { }

namespace Article;

?>



//Example 2
//Some characters are printed before the script

<html></html>
<?php

namespace Article;

?>

 

Why the first namespace? Because multiple namespaces can be created in the same script file.

Next, I created two namespaces and added a Comment class element for each of them:

<?php

//Create a namespace named 'Article'
namespace Article;

//This Comment belongs to the element of Article space
class Comment { }



//Create a namespace named 'MessageBoard'
namespace MessageBoard;

//This Comment belongs to the element of MessageBoard space
class Comment { }
?>

 

You cannot call other elements directly between different spaces. You need to use the syntax of the namespace:

<?php

namespace Article;

class Comment { }



namespace MessageBoard;

class Comment { }

//Call the Comment class of the current space (MessageBoard)
$comment = new Comment();

//Call Comment class of Article space
$article_comment = new \Article\Comment();

?>

 

As you can see, when calling the Comment class in article space in MessageBoard space, a syntax like file path is used: space name element name

In addition to classes, functions and constants are used the same way. Next, I create new elements for 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 { }

//Calling constants, functions, and classes in the current space
echo PATH; ///message_board
echo getCommentTotal(); //300
$comment = new Comment();

//Calling constants, functions, and classes in the Article space
echo \Article\PATH; ///article
echo \Article\getCommentTotal(); //100
$article_comment = new \Article\Comment();

?>

 

Then I did get the element data of Article space.

 

 

Subspace

The call syntax of namespace is just as reasonable as the file path, which allows us to customize the subspace to describe the relationship between each space.

Sorry, I forgot to say that article and message board are both in the same blog project. If namespace is used to express their relationship, it is as follows:

 

<?php

//I use this namespace to represent the article module under the blog
namespace Blog\Article;

class Comment { }



//I use this namespace to represent the message board module under the blog
namespace Blog\MessageBoard;

class Comment { }

//Calling the class of the current space
$comment = new Comment();

//Class calling Blog\Article space
$article_comment = new \Blog\Article\Comment();

?>

 

In addition, subspaces can define many levels, such as Blog\Article\Archives\Date

 

 

public space

I have a common_inc.php script file, which contains some useful functions and classes:

<?php

function getIP() { }

class FilterXSS { }

?>

 

The script is introduced into a namespace, and the elements in the script will not belong to this namespace. If no other namespace is defined in this script, its elements will always be in the public space:

<?php

namespace Blog\Article;

//Import script file
include './common_inc.php';

$filter_XSS = new FilterXSS(); //A fatal error occurred: the Blog\Article\FilterXSS class could not be found

$filter_XSS = new \FilterXSS(); //correct


?>

 

The way to call the public space is to directly add \ 'before the element name, otherwise the PHP parser will think that I want to call the element in the current space. In addition to the custom elements, including PHP's own elements, all belong to the public space.

It's worth mentioning that functions and constants in public space can be called normally without adding \ (I don't understand why PHP does this), but in order to distinguish elements correctly, it's recommended to add \ 'when calling functions

 

 

Nomenclature

Before we talk about aliases and imports, we need to know the terms about the three names of spaces and how PHP parses them. The official documents are very good, so I just used them.

  1. An unqualified name, or a class name without a prefix, such as $comment = new Comment();. If the current namespace is Blog\Article, Comment will be resolved to Blog\Article\Comment. If the code using Comment is not included in any namespace (in global space), the Comment is resolved to Comment.
  2. A qualified name, or a name with a prefix, such as $Comment = new Article\Comment();. If the current namespace is a Blog, comments will be resolved to Blog\Article\Comment. If the code using Comment is not included in any namespace (in global space), the Comment is resolved to Comment.
  3. The fully qualified name, or the name containing the global prefix operator, for example, $Comment = new \Article\Comment();. In this case, Comment is always resolved to the literal name article \ Comment in the code.

 

In fact, these three kinds of names can be compared to file names (such as comment.php), relative path names (such as. / article/comment.php), absolute path names (such as / blog/article/comment.php), which may be easier to understand.

I have used several examples to show them:

<?php

//Create space Blog
namespace Blog;

class Comment { }

//Unqualified name, indicating the current Blog space
//This call will be resolved to Blog\Comment();
$blog_comment = new Comment();

//Qualified name, indicating relative to Blog space
//This call will be resolved to Blog\Article\Comment();
$article_comment = new Article\Comment(); //There is no diagonal bar in front of the class\

//Fully qualified name, indicating absolute in Blog space
//This call will be resolved to Blog\Comment();
$article_comment = new \Blog\Comment(); //Class with diagonal bar in front\

//Fully qualified name, indicating absolute in Blog space
//This call will be resolved to Blog\Article\Comment();
$article_comment = new \Blog\Article\Comment(); //Class with diagonal bar in front\



//Create the sub space Article of Blog
namespace Blog\Article;

class Comment { }


?>

 

In fact, I have been using unqualified names and fully qualified names before, and now they can finally call out their names.

 

 

Aliases and imports

Aliases and imports can be seen as a shortcut to calling namespace elements. PHP does not support importing functions or constants.

They are all implemented by using the use operator:

<?php

namespace Blog\Article;

class Comment { }



//Create a BBS space (I have plans to open a forum)
namespace BBS;

//Import a namespace
use Blog\Article;
//Elements can be called with qualified names after importing a namespace
$article_comment = new Article\Comment();

//Use alias for namespace
use Blog\Article as Arte;
//Use alias instead of space name
$article_comment = new Arte\Comment();

//Import a class
use Blog\Article\Comment;
//The element can be called with an unqualified name after the class is imported
$article_comment = new Comment();

//Use alias for class
use Blog\Article\Comment as Comt;
//Use alias instead of space name
$article_comment = new Comt();

?>

 

I noticed what would happen if the current space had the same name element when the element was imported? It's clear that a fatal error will result.

For example:

<?php

namespace Blog\Article;

class Comment { }



namespace BBS;

class Comment { }

Class Comt { }


//Import a class
use Blog\Article\Comment;
$article_comment = new Comment(); //Conflict with Comment in current space, fatal error in program

//Use alias for class
use Blog\Article\Comment as Comt;
$article_comment = new Comt(); //Conflict with Comt in current space, fatal error in program

?>

 

 

Dynamic call

PHP provides the NAMESPACE keyword and the dynamic access element of the magic constant, which can be accessed dynamically by combining strings:

<?php

namespace Blog\Article;

const PATH = '/Blog/article';

class Comment { }


//The namespace keyword represents the current space
echo namespace\PATH; ///Blog/article
$comment = new namespace\Comment();

//The value of the magic constant "NAMESPACE" is the current space name
echo __NAMESPACE__; //Blog\Article
//Can be combined into a string and called
$comment_class_name = __NAMESPACE__ . '\Comment';
$comment = new $comment_class_name();

?>

 

String form call problem

In the above dynamic call example, we see the dynamic call method in the form of string. If you want to use this method, you should pay attention to two problems.

1. Special characters may be escaped when using double quotation marks

<?php

namespace Blog\Article;

class name { }

//I want to call Blog\Article\name
$class_name = __NAMESPACE__ . "\name"; //But \ n will be escaped as a newline character

$name = new $class_name(); //Fatal error occurred

?>

 

2. Will not be considered a qualified name

When PHP compiles the script, it determines the space of the elements and the import situation. When parsing scripts, string calls can only be considered as unqualified names and fully qualified names, but never qualified names.

<?php

namespace Blog;

//Import Common class
use Blog\Article\Common;
//I want to call Blog\Article\Common with an unqualified name
$common_class_name = 'Common';
//Actually, it will be treated as an unqualified name, which means the Common class of the current space, but my current class does not create a Common class
$common = new $common_class_name(); //Fatal error occurred: Common class does not exist

//I want to call Blog\Article\Common with a qualified name
$common_class_name = 'Article\Common';
//Actually, it will be treated as a fully qualified name, which means the Common class under the Article space, but I only define the Blog\Article space instead of the Article space
$common = new $common_class_name(); //Fatal error occurred: Article\Common class does not exist


namespace Blog\Article;

class Common { }

?>

 

 

summary

I've just touched the PHP namespace, and I can't give some advice without practice. I personally think that the function and function of namespace are very powerful. If you want to write plug-ins or general libraries, you don't need to worry about duplicate names. However, if the project goes on to a certain extent and needs to add a namespace to solve the problem of duplicate names, I don't think the workload will be less than refactoring names. We also have to admit that its syntax will add a certain degree of complexity to the project, so we should plan it well from the beginning of the project and make a naming standard.

Buy me a cup of coffee :)

Posted by Hikari on Wed, 18 Dec 2019 02:03:54 -0800