php命名空间

今天,刚好要写开源项目的后台数据了,所以学习了一下php的命名空间,收获多多,所以总结了一下这篇文章,好了,废话不多说,上代码吧

我们该如何命名空间呢?

<?php
// 使用命名空间的关键字namespace命名
namespace Test;
echo "ok";
echo __NAMESPACE__;

在书写命名空间要避免以下命名方式

<?php 
// 错误示范
// 特别要注意的是,如果是命名空间的最前面是不能有其他代码存在的
$path = '';
class Comment {

}
namespace Article;

// 第二种示范
<p>
   这是第二种示范
</p>

namespace Test;

// 也就是说第一个命名空间namespace 的前面只能是namespace,不能有其他代码
// 否则像上面两种情况的话,是会报错的,
// 因为在同一个脚本中可以有多个命名空间	

命名空间就像文件夹里面找文件一样

<?php
// 我们顺便给这个脚本添加两个命名空间
namespace Article;
class Article {
	public function write() {
		echo "写文章";
	}
}
// 我在Article命名空间调用Comment的类,变量,函数,方法等。
$comment = new \Comment\Comment();
$comment->post();

namespace Comment;
class Comment {
	public function post() {
		echo "发表评论";
	}
}

// 在不同的命名空间我们需要带上自己的命名空间去调用自己的类,函数,方法,变量等
// 例如我在Comment命名空间调用Article命名空间的write方法
$article = new \Article\Article();
$article->write();

// 其实命名空间有点像那个文件中找文件一个
// \Article\Article
// \Comment\Comment

除了可以定义类名,我们也可以给命名空间定义自己的函数,变量

<?php
// 我们顺便给这个脚本添加两个命名空间
// 除了定义类之外,我们可以在各自的命名空间各自的常量,变量,函数
namespace Article;
const PATH = "/article";
function getArticlePath() {
	return PATH;
}

class Article {
	public function write() {
		echo "写文章";
		echo "<br/>";
	}
}
// 我在Article命名空间调用Comment的类,变量,函数,方法等。
$comment = new \Comment\Comment();
$comment->post();

namespace Comment;
// 静态变量
const PATH = '/comment';
// 函数
function getCommentPath() {
	return PATH;
}
class Comment {
	public function post() {
		echo "发表评论";
		echo "<br>";
	}
}

// 在不同的命名空间我们需要带上自己的命名空间去调用自己的类,函数,方法,变量等
// 例如我在Comment命名空间调用Article命名空间的write方法
$article = new \Article\Article();
$article->write();

// 其实命名空间有点像那个文件中找文件一个
// \Article\Article
// \Comment\Comment
// 访问变量和方法
echo "\Article\PATH".\Article\PATH;
echo "<br/>";
echo "\Comment\PATH".\Comment\PATH;
echo "<br/>";
echo "Article\getArticlePath".\Article\getArticlePath();
echo "<br/>";
echo "Comment\getCommentPath".\Comment\getCommentPath();
echo "<br/>";

命名空间的子命名空间

<?php
// 子空间的命名
// 比如下面两个空间都在Blog这个空间里面
// 就像大目录下面有文件夹一样
// 我们顺便给这个脚本添加两个命名空间
// 除了定义类之外,我们可以在各自的命名空间各自的常量,变量,函数
namespace Blog\Article;
const PATH = "blog/article";
function getArticlePath() {
	return PATH;
}

class Article {
	public function write() {
		echo "写文章";
		echo "<br/>";
	}
}
// 我在Article命名空间调用Comment的类,变量,函数,方法等。
$comment = new \Blog\Comment\Comment();
$comment->post();

namespace Blog\Comment;
// 静态变量
const PATH = 'blog/comment';
// 函数
function getCommentPath() {
	return PATH;
}
class Comment {
	public function post() {
		echo "发表评论";
		echo "<br>";
	}
}

// 在不同的命名空间我们需要带上自己的命名空间去调用自己的类,函数,方法,变量等
// 例如我在Comment命名空间调用Article命名空间的write方法
$article = new \Blog\Article\Article();
$article->write();

// 其实命名空间有点像那个文件中找文件一个
// \Article\Article
// \Comment\Comment
// 访问变量和方法
echo "Blog\Article\PATH".\Blog\Article\PATH;
echo "<br/>";
echo "\Blog\Comment\PATH".\Blog\Comment\PATH;
echo "<br/>";
echo "\Blog\Article\getArticlePath".\Blog\Article\getArticlePath();
echo "<br/>";
echo "\Blog\Comment\getCommentPath".\Blog\Comment\getCommentPath();
echo "<br/>";
// 而且,子空间还可以定义很多层次,比如说 Blog\Article\Archives\Date

引入公共文件,如果没有自己的命名空间,就始终是公共的命名空间,

现在我们创建一个common_inc.php

<?php
// 这个文件我们当作是公共的空间
// 可以定义一些共用的脚本
// 在一个命名空间里引入这个脚本,脚本里的元素不会归属到这个命名空间。如果这个脚本里没有定义其它命名空间,它的元素就始终共同的命名空间中
function getIP() {

}

class FilterXSS {

}



下面我们引入公共文件common_inc.php

<?php
// 现在我们在这个命名空间引入刚才的公共文件
namespace Blog\Article;
include './common_inc.php';

// $filterxss = new FilterXSS();//这个会发生一个致命的错误,系统会找不到这个类名
$filterxss = new \FilterXSS();// '\'表示是一个公共的命名空间,这样系统就能获取到这个类了
/**
调用公共空间的方式是直接在元素名称前加 \ 就可以了,否则PHP解析器会认为我想调用当前空间下的元素。除了自定义的元素,还包括PHP自带的元素,都属于公共空间。
要提一下,其实公共空间的函数和常量不用加 \ 也可以正常调用(不明白PHP为什么要这样做),但是为了正确区分元素,还是建议调用函数的时候加上 \


 */

类比三种文件路径,绝对路径,相对路劲,当前路劲

名称术语 在说别名和导入之前,需要知道关于空间三种名称的术语,以及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关键字和__NAMESPACE__魔法常量动态的访问元素,__NAMESPACE__可以通过组合字符串的形式来动态访问: -->



<?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();

?>

字符串拼接问题

<!-- 字符串形式调用问题 -->

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

 

<!-- 1. 使用双引号的时候特殊字符可能被转义 -->



<?php
 

namespace Blog\Article;

class name { }

//我是想调用Blog\Article\name
// $class_name = __NAMESPACE__ . "\name"; //但是\n将被转义为换行符
$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 = '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 { }

?>

发布于 2019-01-03 21:27