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。