PHP中的命名空间

PHP中的命名空间

更好排版:https://www.zybuluo.com/phper/note/65479

php是世界上最伟大的语言!霸气开场(^__^)

1. 什么是命名空间?

命名空间对应的英文是namespace,所以翻译成中文叫命名空间,在很多的语言中,都有这个namespace,那么它用来干嘛呢?说简单点就是为了避免代码命名重复。因为包括php在内的很多语言,是不允许function name 或者class name重复的,如果你同时require 2个class ,如果调用的对应的class name是一样,系统是会报错的。所有,一般的对面对象的语言都会有namespace,用来避免这种情况出现。

php在5.3之前是不支持namespace的,所以很多程序员的class name 和function name经常会用class_name_1class_name_2class_name_3用_隔开等类似这样的方式来避免类的重复,很是这样却不美观和优雅,而且维护起来比较费劲很难理解。于是php在5.3重磅突出了namespace。

举个例子,先常规的写,不使用namespace

现在我的同一个目录下3个php文件,分别是:index.phpname.phpgender.php。 
三个文件很简单,就是输出一段很简单文字的代码。

name.php

  
  
  
  
  1. <?php
  2. class info {
  3. public static function get_info()
  4. {
  5. echo 'hello word 1';
  6. }
  7. }

gender.php

  
  
  
  
  1. <?php
  2. class info {
  3. public static function get_info()
  4. {
  5. echo 'hello word 2';
  6. }
  7. }

然后在index.php分别rquire这2个文件

  
  
  
  
  1. <?php
  2. require './name.php';
  3. require './gender.php';
  4. info::get_info();
  5. info::get_info();

name.phpgender.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

  
  
  
  
  1. <?php
  2. namespace Foo;
  3. class info {
  4. public static function get_info()
  5. {
  6. echo 'hello word 1';
  7. }
  8. }

gender.php

  
  
  
  
  1. <?php
  2. namespace Fee;
  3. class info {
  4. public static function get_info()
  5. {
  6. echo 'hello word 2';
  7. }
  8. }

然后在index.php分别rquire这2个文件,并用namespace的方式调用。

  
  
  
  
  1. <?php
  2. require './name.php';
  3. require './gender.php';
  4. Foo\info::get_info();
  5. Fee\info::get_info();

我们刷新下index.php, 看看结果是啥,看,输出的就是我们想要的结果,没有报错:

hello word 1hello word 2

function name也是不能重复的,这里就不举例了,原理是一样的。

2. 为什么目前国内使用率不高?

截止到目前为止,老实话其实我也没接触过任何关于php的命名空间的项目或者代码,我现在仔细想想为什么会这样呢。大概或许是这几点吧:

  • 目前国内的php版本已经处于5.3*, 而且还有很多处于5.2, php的命名空间的更新是在5.3版本上加入的,所以使用率不是很高。
  • 貌似目前的国内的开源的项目或者框架基本没用namespace,或许也有这个因素的影响吧,大家开发写代码想到的就是如何运用好MVC和面向对象,想起用namespace的少之又少。
  • namespace 对比PHP中的其他语法还是有点羞涩难懂的,而且一些很诡异的书写方式和命名方式,这或许也是一个比较大的影响因素,再加上平时项目中使用率不高,基本上也就不会用它了

3. 在 PHP类文件中使用namespace

下面我们进入正题,真正意义上来学一下php中的命名空间。php的命名空间其实还是非常简单的。

如何声明一个namespace

前面一个例子呢,简单的说了一下如何声明,现在着重说一下,先提前说明下,稍显变态。

像这样子申明:

namespce name

先看个例子:

  
  
  
  
  1. <?php
  2. namespace FOO
  3. class info
  4. {
  5. public function test()
  6. {
  7. echo 'HELLO WORD!';
  8. }
  9. }

必须用关键字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

所以以下几个是错误的,会报错:

  
  
  
  
  1. <?php
  2. $info = array();
  3. namespace FOO
  4. class info
  5. {
  6. public function test()
  7. {
  8. echo 'HELLO WORD!';
  9. }
  10. }
  
  
  
  
  1. <?php
  2. echo 345;
  3. namespace FOO
  4. class info
  5. {
  6. public function test()
  7. {
  8. echo 'HELLO WORD!';
  9. }
  10. }
  
  
  
  
  1. <?php
  2. header("Content-type: text/html; charset=utf-8");
  3. namespace FOO
  4. class info
  5. {
  6. public function test()
  7. {
  8. echo 'HELLO WORD!';
  9. }
  10. }

还有最重要的一个容易忽略的就是<?php,这个声明是php的文件的标记也必须得定格写,前面不能有空格, 不然也会报错。这一点非常重要,极其容易忽略,就产生错误了。

<?php前面有空格,也会报错。

  
  
  
  
  1. <?php //前面有个空格,也会报错
  2. namespace FOO
  3. class info
  4. {
  5. public function test()
  6. {
  7. echo 'HELLO WORD!';
  8. }
  9. }

一个namespace的name的书写方式

上面的几个例子中,我们取的命名空间的name 叫 FooFee ,当然这只是一个例子,我们在取名字的时候必须得是有意义的。按照PSR-0的规范要求呢,这个名字必须得有一个上级的Vendor Name,可以理解为你的项目文件夹的名字,这样的目的呢,第一是为了防止namespace的name 也重复,第二是为了更好的定位文件的位置。也许有点看不懂,举个例子:

假如gender.php 和 name.php 文件中的class name 都取名为:info , 那么必须要设置2级的namespace。

gender.php

  
  
  
  
  1. <?php
  2. namespace App\Fee;
  3. class info {
  4. public static function get_info()
  5. {
  6. echo 'hello word 2';
  7. }
  8. }

name.php

  
  
  
  
  1. <?php
  2. namespace App\Foo;
  3. class info {
  4. public static function get_info()
  5. {
  6. echo 'hello word 1';
  7. }
  8. }

namespace的名字叫App\Foo 和 App\Fee, App就是Vendor name 也就是项目的目录。这样就很好的区分了。

如果,name.php 和 gender.php 中的class name 不一样,也就不会重复了,理论上可以不用命名空间,但是现在用命名空间不仅仅是为了防止重复,现在同样也是为了定位这个文件的目录,为了好快速找到。所以,就只需一层Vendor name 就可以了

gender.php

  
  
  
  
  1. <?php
  2. namespace App;
  3. class gender {
  4. public static function get_info()
  5. {
  6. echo 'hello word 2';
  7. }
  8. }

name.php

  
  
  
  
  1. <?php
  2. namespace App;
  3. class name {
  4. public static function get_info()
  5. {
  6. echo 'hello word 1';
  7. }
  8. }

上面的我们都将它们命名空间为APP,因为它们的class name不一样,所以组成的访问类的方式:APP\gender::get_info(); 和App\name::get_info(); 也就不一样。也就不存在重复的关系。我们在下面将如何访问一个namespace时会继续讲到。

name命名规范 和php中变量的命名规则一样,什么首字母不能是数字啊。只能有数字,字母,下划线_组成,也不能是系统保留关键字等。(\这个符号可以用的,因为是在namespace中用来分割目录的)

namespace的访问

上面我用了大幅篇章来声明如何定义一个namespace,当然还有一些很诡异的申明方式,我们放到后面起说。现在来说,如何访问一个namespace。

访问一个namespace其实和访问一个class 类一模一样,先是导入class ,再是new 适用等。

第1种方式

像这样子访问调用:

Vendor\namespce\class

gender.php

  
  
  
  
  1. <?php
  2. namespace App;
  3. class gender {
  4. //静态方法,可以直接用::访问
  5. public static function get_info()
  6. {
  7. echo 'hello word 2';
  8. }
  9. }

name.php

  
  
  
  
  1. <?php
  2. namespace App;
  3. class name {
  4. public function get_info()
  5. {
  6. echo 'hello word 1';
  7. }
  8. }
  
  
  
  
  1. <?php
  2. require './gender.php';
  3. require './name.php';
  4. //static function 直接使用
  5. App\gender::get_info();
  6. //一般方式,先new,再调用
  7. $name = new App\name;
  8. $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

  
  
  
  
  1. <?php
  2. require './gender.php';
  3. require './name.php';
  4. //第1种 use 用来导入gender类
  5. use App\gender;
  6. gender::get_info();
  7. use App\name;
  8. $name_object = new name;
  9. $name_object->get_info();
  10. //第2种 use ** as alise_name 取别名
  11. use App\gender as alise_gender;
  12. alise_gender::get_info();
  13. use App\name as alise_name;
  14. $alise_name_object = new alise_name;
  15. $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其他的知识点的。在下面接着说。

4. 在php function文件中使用namespace

大多数适用namespace其实是在类文件(class)中使用的,在function 文件中也是可以使用的,也能够防止重复。但是用的很少,使用起来也很蛋疼。

还是看例子:

有一个height.php文件,用namespace申明一个命名空间App

  
  
  
  
  1. <?php
  2. namespace App;
  3. function test()
  4. {
  5. echo ' this is a namespace function test';
  6. }

然后在index.php中require并引用这个namespace App

  
  
  
  
  1. <?php
  2. require './height.php';
  3. //第一种方式调用,和之前一样
  4. App\test();
  5. //第二种方式调用,使用use, 必须配合as 使用,不然报错
  6. use App;
  7. test(); //报错
  8. //正确的使用方式
  9. use App as anthorApp;
  10. anthorApp\test();

上面一个报错的使用是我们自己想当然,想着没有class name了,是不是就可以直接使用function name了,结果就报错了。因为不管使用好是不使用use,当得像这样子访问class\function。所以,既然function没有class,那么我们就可以使用use namespace as class生成一个别名anthorApp,再用这个anthorApp\test()就可以访问了。

所以,你看到的这篇文件中这一处是错误的:PHP V5.3 中的新特性,第 3 部分: 名称空间 :

  
  
  
  
  1. /* File3.php */
  2. <?php
  3. include './Foo.php';
  4. use Foo;
  5. bar(); // outputs "calling bar...."; //这种方式是错的。
  6. ?>

所以总结下: 如果我们用namespace声明 function 文件时,最好直接使用App\test()调用吧,如果想用use关键字,必须要用as一个别名。

5. 在php中混合使用各种

什么叫混合使用呢。就是既使用namespace声明class,又声明function,又单独使用,虽然有点变态,但是为了学习它,为了找到namespace的精髓,我也是蛮拼的。

直接上代码吧:

height.php 文件中,用namespace 同时声明的function 和 class

  
  
  
  
  1. <?php
  2. namespace App;
  3. function test()
  4. {
  5. echo ' this is a namespace function test';
  6. }
  7. class height
  8. {
  9. public static function test()
  10. {
  11. echo 'hello word 3';
  12. }
  13. }

在 function.php 写的是正常普通的function 和 class

  
  
  
  
  1. <?php
  2. function test()
  3. {
  4. echo ' this is a function test';
  5. }
  6. class height {
  7. public static function test()
  8. {
  9. echo 'hello word 4';
  10. }
  11. }

好。那么这么变态的东西,如何访问呢。仔细想想上面说的那么多的,其实很快就可以写出来,而且不会报错:

index.php

  
  
  
  
  1. <?php
  2. require './height.php';
  3. require './function.php';
  4. // 调用namespace的function 和 class 直接调
  5. App\test();
  6. App\height::test();
  7. //调用namespace的function 和 class 使用use
  8. use App as anthorApp;
  9. anthorApp\test();
  10. use App\height;
  11. height::test();
  12. use App\height as anthorClssApp;
  13. anthorClssApp::test();
  14. //调用普通的
  15. test();
  16. 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


你可能感兴趣的:(PHP中的命名空间)