PHP命名空间

PHP 命名空间(namespace)是在PHP 5.3中加入的,如果你学过C#和Java,那命名空间就不算什么新事物。 不过在PHP当中还是有着相当重要的意义。

PHP 命名空间可以解决以下两类问题: 

    用户代码与PHP内部的类/函数/常量之间的名字冲突。

    创建别名(或简短)的名称,提高源代码的可读性。

默认情况下,所有常量、类和函数名都放在全局空间下,就和PHP支持命名空间之前一样。
如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间

< ?php  
// 定义代码在 'MyProject' 命名空间中  
namespace MyProject;  
 
// ... 代码 ...  

//也可以在同一个文件中定义不同的命名空间代码
namespace MyProject1;  
// MyProject1 命名空间中的PHP代码  
 
namespace MyProject2;  
// MyProject2 命名空间中的PHP代码    
 
// 另一种语法
namespace MyProject3 {  
 // MyProject3 命名空间中的PHP代码    
}  

?>

 

在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。

<?php
declare(encoding='UTF-8'); //定义多个命名空间和不包含在命名空间中的代码
namespace MyProject {
    const CONNECT_OK = 1;
    class Connection { /* ... */ }
    function connect() { /* ... */  }
}

namespace { // 全局代码
    session_start();
    $a = MyProject\connect();
    echo MyProject\Connection::start();
}
?>

以下代码会出现语法错误:

<html>
<?php
namespace MyProject; // 命名空间前出现了“<html>” 会致命错误 - 命名空间必须是程序脚本的第一条语句
?>

命名空间使用

PHP 命名空间中的类名可以通过三种方式引用:

限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或 foo::staticmethod();。如果当前命名空间是 currentnamespace,foo 将被解析为 currentnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。 警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。~~无命名空间前缀的引用,默认在当前命名空间查找,然后到全局命名空间找 

限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod();。如果当前的命名空间是 currentnamespace,则 foo 会被解析为 currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespace\foo。 ~~带相对命名空间前缀的(类似相对路径)引用,自动在开头添加调用代码所处的命名空间

完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespace\foo。~~带绝对命名空间前缀的引用(类似绝对路径) 引用路径已明确 不用查找

<?php
//file1.php
namespace Foo\Bar\subnamespace; 

const FOO = 1;
function foo() {}
class foo
{
    static function staticmethod() {}
}
?>
      <?php
      namespace Foo\Bar;
      include 'file1.php';
      
      const FOO = 2;
      function foo() {}
      class foo
      {
          static function staticmethod() {}
      }
      
      /* 非限定名称 */
      foo(); // 解析为函数 Foo\Bar\foo
      foo::staticmethod(); // 解析为类 Foo\Bar\foo的静态方法staticmethod。
      echo FOO; // resolves to constant Foo\Bar\FOO
      
      /* 限定名称 */
      subnamespace\foo(); // 解析为函数 Foo\Bar\subnamespace\foo
      subnamespace\foo::staticmethod(); // 解析为类 Foo\Bar\subnamespace\foo,
                                        // 以及类的方法 staticmethod
      echo subnamespace\FOO; // 解析为常量 Foo\Bar\subnamespace\FOO
                                        
      /* 完全限定名称 */
      \Foo\Bar\foo(); // 解析为函数 Foo\Bar\foo
      \Foo\Bar\foo::staticmethod(); // 解析为类 Foo\Bar\foo, 以及类的方法 staticmethod
      echo \Foo\Bar\FOO; // 解析为常量 Foo\Bar\FOO
      ?>

      在命名空间内部访问全局类、函数和常量:

      <?php
      namespace Foo;
      
      function strlen() {}
      const INI_ALL = 3;
      class Exception {}
      
      $a = \strlen('hi'); // 调用全局函数strlen
      $b = \INI_ALL; // 访问全局常量 INI_ALL
      $c = new \Exception('error'); // 实例化全局类 Exception
      ?>

      使用命名空间:后备全局函数/常量

      在一个命名空间中,当 PHP 遇到一个非限定的类、函数或常量名称时,它使用不同的优先策略来解析该名称。

      • 类名称总是解析到当前命名空间中的名称(找不到就报错咯)。因此在访问系统内部或不包含在命名空间中的类名称时,必须使用完全限定名称
      • 函数和常量来说,如果当前命名空间中不存在该函数或常量,PHP 会退而使用全局空间中的函数或常量。
      <?php
      namespace A\B\C;
      class Exception extends \Exception {}
      
      $a = new Exception('hi'); // $a 是类 A\B\C\Exception 的一个对象
      $b = new \Exception('hi'); // $b 是类 Exception 的一个对象
      
      $c = new ArrayObject; // 致命错误, 找不到 A\B\C\ArrayObject 类
      ?>

      全局空间

      如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀 \ 表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。

      <?php
      namespace A\B\C;
      
      /* 这个函数是 A\B\C\fopen */
      function fopen() { 
           /* ... */
           $f = \fopen(...); // 调用全局的fopen函数
           return $f;
      } 
      ?>
      0 条评论
      发表一条评论