PHP中的命名空间
更好排版:https://www.zybuluo.com/phper/note/65479
php是世界上最伟大的语言!霸气开场(^__^)
命名空间对应的英文是namespace
,所以翻译成中文叫命名空间
,在很多的语言中,都有这个namespace,那么它用来干嘛呢?说简单点就是为了避免代码命名重复。因为包括php在内的很多语言,是不允许function name
或者class name
重复的,如果你同时require 2个class ,如果调用的对应的class name
是一样,系统是会报错的。所有,一般的对面对象的语言都会有namespace
,用来避免这种情况出现。
php在5.3之前是不支持namespace
的,所以很多程序员的class name
和function name
经常会用class_name_1
,class_name_2
,class_name_3
用_隔开等类似这样的方式来避免类的重复,很是这样却不美观和优雅,而且维护起来比较费劲很难理解。于是php在5.3重磅突出了namespace。
举个例子,先常规的写,不使用namespace
现在我的同一个目录下3个php文件,分别是:index.php
,name.php
,gender.php
。
三个文件很简单,就是输出一段很简单文字的代码。
name.php
<?php
class info {
public static function get_info()
{
echo 'hello word 1';
}
}
gender.php
<?php
class info {
public static function get_info()
{
echo 'hello word 2';
}
}
然后在index.php分别rquire
这2个文件
<?php
require './name.php';
require './gender.php';
info::get_info();
info::get_info();
name.php
和gender.php
里的类名字是一样的,都叫info
,或许你会反问我,你是傻逼吗?你不会给这2个类取不一样的名字啊。因为这里只是小测试小项目,你当然会取不一样的名字。但是比如你用composer
导入其他人的开源库的代码,肯定是会有class name
是一样的,这一点是毋庸置疑的,所以你还是无法避免这个问题的。
这时候,你运行下index.php就直接报致命错误了的,说类重新声明了。
Fatal error: Cannot redeclare class info in D:\wamp\www\testphp\namespace\gender.php on line 3
下面再简单说下如何用namespace避免重复,还是这个例子,下面会着重讲。
我们加入namespace
看下:
name.php
<?php
namespace Foo;
class info {
public static function get_info()
{
echo 'hello word 1';
}
}
gender.php
<?php
namespace Fee;
class info {
public static function get_info()
{
echo 'hello word 2';
}
}
然后在index.php分别rquire
这2个文件,并用namespace的方式调用。
<?php
require './name.php';
require './gender.php';
Foo\info::get_info();
Fee\info::get_info();
我们刷新下index.php
, 看看结果是啥,看,输出的就是我们想要的结果,没有报错:
hello word 1hello word 2
function name
也是不能重复的,这里就不举例了,原理是一样的。
截止到目前为止,老实话其实我也没接触过任何关于php的命名空间的项目或者代码,我现在仔细想想为什么会这样呢。大概或许是这几点吧:
下面我们进入正题,真正意义上来学一下php中的命名空间。php的命名空间其实还是非常简单的。
前面一个例子呢,简单的说了一下如何声明,现在着重说一下,先提前说明下,稍显变态。
像这样子申明:
namespce name
先看个例子:
<?php
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
必须用关键字namespace
来做声明,后面加上命名空间的名字。这个关键字一行必须写在一个php文件的最开头,前面不能有任何的语句
,额,这一点是有点变态哈,但是也还能忍受。所以,包括ehco 222;
, $info = array()
等这一系列的语句的都不能写在namespace
前面。不然就会报致命错误:
Fatal error: Namespace declaration statement has to be the very first statement in the script in D:\wamp\www\testphp\namespace\gender.php on line 3
所以以下几个是错误的,会报错:
<?php
$info = array();
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
<?php
echo 345;
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
<?php
header("Content-type: text/html; charset=utf-8");
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
还有最重要的一个容易忽略的就是<?php
,这个声明是php的文件的标记也必须得定格写,前面不能有空格
, 不然也会报错。这一点非常重要,极其容易忽略,就产生错误了。
<?php
前面有空格,也会报错。
<?php //前面有个空格,也会报错
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
上面的几个例子中,我们取的命名空间的name 叫 Foo
和Fee
,当然这只是一个例子,我们在取名字的时候必须得是有意义的。按照PSR-0
的规范要求呢,这个名字必须得有一个上级的Vendor Name
,可以理解为你的项目文件夹的名字,这样的目的呢,第一是为了防止namespace的name 也重复,第二是为了更好的定位文件的位置。也许有点看不懂,举个例子:
假如gender.php 和 name.php 文件中的class name 都取名为:info
, 那么必须要设置2级的namespace。
gender.php
<?php
namespace App\Fee;
class info {
public static function get_info()
{
echo 'hello word 2';
}
}
name.php
<?php
namespace App\Foo;
class info {
public static function get_info()
{
echo 'hello word 1';
}
}
namespace的名字叫App\Foo
和 App\Fee
, App就是Vendor name
也就是项目的目录。这样就很好的区分了。
如果,name.php
和 gender.php
中的class name
不一样,也就不会重复了,理论上可以不用命名空间,但是现在用命名空间不仅仅是为了防止重复,现在同样也是为了定位这个文件的目录,为了好快速找到。所以,就只需一层Vendor name 就可以了
:
gender.php
<?php
namespace App;
class gender {
public static function get_info()
{
echo 'hello word 2';
}
}
name.php
<?php
namespace App;
class name {
public static function get_info()
{
echo 'hello word 1';
}
}
上面的我们都将它们命名空间为APP
,因为它们的class name
不一样,所以组成的访问类的方式:APP\gender::get_info();
和App\name::get_info();
也就不一样。也就不存在重复的关系。我们在下面将如何访问一个namespace时会继续讲到。
name命名规范 和php中变量的命名规则一样,什么首字母不能是数字啊。只能有数字,字母,下划线_组成,也不能是系统保留关键字等。(\这个符号可以用的,因为是在namespace中用来分割目录的)
上面我用了大幅篇章来声明如何定义一个namespace,当然还有一些很诡异的申明方式,我们放到后面起说。现在来说,如何访问一个namespace。
访问一个namespace其实和访问一个class 类一模一样,先是导入class ,再是new 适用等。
第1种方式
像这样子访问调用:
Vendor\namespce\class
gender.php
<?php
namespace App;
class gender {
//静态方法,可以直接用::访问
public static function get_info()
{
echo 'hello word 2';
}
}
name.php
<?php
namespace App;
class name {
public function get_info()
{
echo 'hello word 1';
}
}
<?php
require './gender.php';
require './name.php';
//static function 直接使用
App\gender::get_info();
//一般方式,先new,再调用
$name = new App\name;
$name->get_info();
和调用普通的类一样,先require
进来,只不过现在的类名
变成了:在class name
前面多加了一个namespace name
并用\
隔开,如果是静态方法就直接::function name
调用就可以了。如果是常规方法就先new
再调用function name
。
第2中方式:使用use关键字
用过其他语言中的namespace的或许知道有一个关键字use
来到导入命名空间的,php中也是可以的。我们试一下:
像这样子访问调用:
use Vendor\namespce\class
class::function
index.php
<?php
require './gender.php';
require './name.php';
//第1种 use 用来导入gender类
use App\gender;
gender::get_info();
use App\name;
$name_object = new name;
$name_object->get_info();
//第2种 use ** as alise_name 取别名
use App\gender as alise_gender;
alise_gender::get_info();
use App\name as alise_name;
$alise_name_object = new alise_name;
$alise_name_object->get_info();
第1中是用use
用来导入的,导入了App\gender
类,然后就可以直接调用gender::静态方法
或者new name
再来调用普通方法。
第2种是用use as alise_name
方法取了一个别名而已,用法和第一种类似一致。
我是推荐用第1种的,直接使用use导入就好了。用as
别名反而容易造成错误和复杂度,而且你使用use
的方式,已经是将namespace
给省略掉了,变成正常的class调用方式
。一般as
用在namespace申明function
时候用,在下面会讲到。
OK. php 使用 命名空间基本的东西已经说完了。平时如果使用namespace ,也就上面这些东西了。所以如果掌握了,基本也就没问题了。
但是,我们因为是在学习它,所以还是要继续深挖一些namespace其他的知识点的。在下面接着说。
大多数适用namespace其实是在类文件(class)中使用的,在function 文件中也是可以使用的,也能够防止重复。但是用的很少,使用起来也很蛋疼。
还是看例子:
有一个height.php文件,用namespace申明一个命名空间App
<?php
namespace App;
function test()
{
echo ' this is a namespace function test';
}
然后在index.php中require
并引用这个namespace App
<?php
require './height.php';
//第一种方式调用,和之前一样
App\test();
//第二种方式调用,使用use, 必须配合as 使用,不然报错
use App;
test(); //报错
//正确的使用方式
use App as anthorApp;
anthorApp\test();
上面一个报错的使用是我们自己想当然,想着没有class name
了,是不是就可以直接使用function name
了,结果就报错了。因为不管使用好是不使用use
,当得像这样子访问class\function
。所以,既然function
没有class
,那么我们就可以使用use namespace as class
生成一个别名anthorApp
,再用这个anthorApp\test()
就可以访问了。
所以,你看到的这篇文件中这一处是错误的:PHP V5.3 中的新特性,第 3 部分: 名称空间 :
/* File3.php */
<?php
include './Foo.php';
use Foo;
bar(); // outputs "calling bar...."; //这种方式是错的。
?>
所以总结下: 如果我们用namespace声明 function 文件时,最好直接使用App\test()
调用吧,如果想用use
关键字,必须要用as
一个别名。
什么叫混合使用呢。就是既使用namespace声明class,又声明function,又单独使用,虽然有点变态,但是为了学习它,为了找到namespace的精髓,我也是蛮拼的。
直接上代码吧:
height.php 文件中,用namespace 同时声明的function 和 class
<?php
namespace App;
function test()
{
echo ' this is a namespace function test';
}
class height
{
public static function test()
{
echo 'hello word 3';
}
}
在 function.php 写的是正常普通的function 和 class
<?php
function test()
{
echo ' this is a function test';
}
class height {
public static function test()
{
echo 'hello word 4';
}
}
好。那么这么变态的东西,如何访问呢。仔细想想上面说的那么多的,其实很快就可以写出来,而且不会报错:
index.php
<?php
require './height.php';
require './function.php';
// 调用namespace的function 和 class 直接调
App\test();
App\height::test();
//调用namespace的function 和 class 使用use
use App as anthorApp;
anthorApp\test();
use App\height;
height::test();
use App\height as anthorClssApp;
anthorClssApp::test();
//调用普通的
test();
height::test();
具体就不解释了吧。上面已经说的一目了然了。举这个例子就是为了说明,namespace在重复命名方面很有优势。
好了。php中的namespace基本改讲的也差不多了。也够用了。其实蛮简单的,被我长篇大论说了这么多。OK。
参考资料
http://www.ibm.com/developerworks/cn/opensource/os-php-5.3new3/
http://www.cnblogs.com/thinksasa/p/3423480.html
http://www.w3cschool.cc/php/php-namespace.html