namespace讲解

作用就是解决引用不同文件中,相同命名的类,函数,常量的冲突

先看例子:

<?php
namespace my\name; // 参考 "定义命名空间" 小节

class MyClass {}
function myfunction() {}
const MYCONST = 1;

$a = new MyClass;
$c = new \my\name\MyClass; // 参考 "全局空间" 小节

$a = strlen('hi'); // 参考 "使用命名空间:后备全局函数/常量" 小节

$d = namespace\MYCONST; // 参考 "namespace操作符和__NAMESPACE__常量" 小节

$d = __NAMESPACE__ . '\MYCONST';
echo constant($d); // 参考 "命名空间和动态语言特征" 小节

上面是一个综合的示例,下面逐个讲解

  1. 声明一个namespace,很简单,在所有代码最前面,写 namespace xxx\yyy; 此时后面的代码就处于这个xxx\yyy虚拟空间中;

  2. 子命名空间namespace MyProject\Sub\Level; 根据psr4标准,应该按目录结构划分namespace的层次;比如App/Http/Model/User.php , 其命名空间为namespace App\Http\Model;

  3. 一个脚本文件中,也可以使用多个namespace,但是不推荐,所以这里不说明;

  4. PHP中是如何知道当前使用的类,函数,常量是哪个namespace中的?
    先看一个简单例子
    demo2.php

     <?php
     namespace x\z;
    
     class demo{}

    demo1.php

     <?php
     namespace x\y;
     include './demo2.php';
    
     class demo{}
     $obj = new demo;    //非限定名称 --- 访问的是 x\y\demo类
     var_dump($obj);        //object(x\y\demo)#1 (0) { }

    如果此时想访问demo2.php中的demo类呢?这样写$obj = new x\z\demo;是报错的,
    错误是Fatal error: Uncaught Error: Class 'x\y\x\z\demo' not found
    可以看到,被识别为 x\y\x\z\demo 的命名空间中了,这种其实就是限定名称;
    可以直接使用完全限定名称来访问\x\z\demo

    当然还有另一种访问方式,使用use,如下:

     namespace x\y;
     include './demo2.php';
     use x\z as c;
    
     class demo{}
     $obj = new c\demo;
     var_dump($obj);        //object(x\z\demo)#1 (0) { }

    总结:可以看到访问一个命名空间中的元素,可以使用非限定,限定,完全限定等方式,非限定一般指当前命名空间下的,限定指当前命名空间下的子命名空间,限定则直接指定为某个命名空间,
    还有一种情况是,当使用非限定时,如果当前namespace找不到访问的函数/常量,则到全局中找;类是不行的;类必须得加 \
    当然使用use则又有点不一样了,后面继续讲解说明;

  5. 命名空间还受到PHP动态语义的影响
    什么意思?我也不懂,直接上例子:
    example1.php:

     <?php
     class classname{}
     function funcname(){}
     const constname = "global";
     ?>

    example2.php:

     <?php
     namespace namespacename;
     class classname{}
     function funcname(){}
     const constname = "namespaced";
     include 'example1.php';
    
     $a = 'classname';
     $obj = new $a;                         // prints classname::__construct
     $b = 'funcname';
     $b();                                 // prints funcname
     echo constant('constname'), "\n";     // prints global
    
     /* note that if using double quotes, "\\namespacename\\classname" must be used */
     $a = '\namespacename\classname';
     $obj = new $a; // prints namespacename\classname::__construct
     $a = 'namespacename\classname';
     $obj = new $a; // also prints namespacename\classname::__construct
     $b = 'namespacename\funcname';
     $b(); // prints namespacename\funcname
     $b = '\namespacename\funcname';
     $b(); // also prints namespacename\funcname
     echo constant('\namespacename\constname'), "\n"; // prints namespaced
     echo constant('namespacename\constname'), "\n"; // also prints namespaced
     ?>

    可以看到,这种方式,相当于前面默认带了全局\ , 记住这一点就行;

  6. namespace关键字和__NAMESPACE__常量
    都是代指当前的命名空间名称,可以抽象的访问当前命名空间内部的元素;namespace就类似”类”的self一样;__NAMESPACE__就是一个命名空间名称的字符串
    注意,全局空间下,_NAMESPACE__是为空字符的

虽然这两个意思差不多,但是实际用的地方还是有所不同,下面是各自的使用示例:
_NAMESPACE__动态创建名称
file2.php

<?php
namespace MyProject\file2;

class name{}

file1.php

    <?php
    namespace MyProject;
    include './file2.php';

    class name{}

    function get($classname)
    {
        $a = __NAMESPACE__ . '\\' . $classname;
        return new $a;
    }

    $obj = get('file2\name');    //object(MyProject\file2\name)#1 (0) { }
    // $obj2 = new MyProject\file2\name;    //这样会报错,解析      为'MyProject\MyProject\file2\name'
    $obj3 = get('name');    // object(MyProject\name)#2 (0) { }
    var_dump($obj, $obj2, $obj3);

关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素

<?php
namespace MyProject;

use blah\blah as mine;         // 别名mine 代指 blah\blah

blah\mine();                 // MyProject\blah\mine() 函数

namespace\blah\mine();         // MyProject\blah\mine() 函数

namespace\func();             // MyProject\func()

namespace\sub\func();         // MyProject\sub\func()

namespace\cname::method();     // MyProject\cname 类 的静态方法 method()

$a = new namespace\sub\cname();     // MyProject\sub\cname

$b = namespace\CONSTANT;             // MyProject\CONSTANT
?>
<?php
//全局空间
namespace\func();                     // 全局下的func()

namespace\sub\func();                 // sub\func()

namespace\cname::method();             // 全局下的cname类的method();

$a = new namespace\sub\cname();     // sub\cname

$b = namespace\CONSTANT;             // 全局CONSTANT
?>
  1. 别名 — Use
    首先通过前面的学习,可以知道,在一个命名空间中,想使用其它命名空间中的元素时,必须得使用完全限定方式,这样会导致引入时,标识符很长,可读性差,如\App\Http\Controller\UserCenter; ; 因此引入别名机制;

使用use引入命名空间,会自动带上全局 \,比如use Foo,use Foo\Bar,实际是\Foo,\Foo\Bar,不然的话,也没有用它的意义了;
并且,use是默认带一个别名的,比如还是上面的,实际的是Foo as Foo , Foo\Bar as Bar
当然也可以自定义use Foo\Bar as B

先看一个简单的示例:
file2.php

<?php
namespace b;
class demo{}

file3.php

<?php
namespace a\b\c;
class demo{}

file1.php

<?php
namespace a;
include './file2.php';
include './file3.php';
class demo{}

$obj = new b\demo;        //这样访问的 a\b\demo,不存在,报错
$obj2 = new a\b\c\demo;    //解析为a\a\b\c\demo,不存在,报错
var_dump($obj);

-----------

namespace a;
include './file2.php';
include './file3.php';
class demo{}
use b;  //等同于 use \b as b;
use a\b\c as file3;

$obj = new b\demo;        //object(b\demo)#1 (0) { }
$obj2 = new file3\demo;    //object(a\b\c\demo)#2 (0) { }
var_dump($obj, $obj2);    

下面直接看各种use使用的实例:

<?php
namespace foo;
use My\Full\Classname as Another;            //给命名空间起一个别名


use My\Full\NSname;                            //与 use My\Full\NSname as NSname 相同


use ArrayObject;                            // 导入一个全局类


use function My\Full\functionName;            // 引入一个My\Full\functionName函数


use function My\Full\functionName as func;    //函数别名


use const My\Full\CONSTANT;                    // 引入一个常量


$obj = new namespace\Another;                 // 实例化 foo\Another 对象

$obj = new Another;                         // 实例化 My\Full\Classname 对象

NSname\subns\func();                         // 调用函数 My\Full\NSname\subns\func

$a = new ArrayObject(array(1));             // 实例化 ArrayObject 对象
// 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象


func();                                     // My\Full\functionName

echo CONSTANT;                                 // My\Full\CONSTANT
?>

为了简化操作,PHP还支持在一行中使用多个use语句

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
?>

导入和动态名称

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 实例化一个 My\Full\Classname 对象
$a = 'Another';
$obj = new $a;      // 实际化一个 Another 对象
?>

另外,导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // instantiates object of class My\Full\Classname
$obj = new \Another; // instantiates object of class Another
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing
$obj = new \Another\thing; // instantiates object of class Another\thing
?>
  1. 全局空间 \
    如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀 \ 表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。
<?php
namespace A\B\C;

/* 这个函数是 A\B\C\fopen */
function fopen() { 
     /* ... */
     $f = \fopen(...); // 调用全局的fopen函数
     return $f;
} 
?>
  1. 后备全局函数/常量
    在一个命名空间中,使用一个非限定的类、函数或常量名称时,类名称总是解析到当前命名空间中的名称。因此在访问系统内部或不包含在命名空间中的类名称时,必须使用完全限定名称,例如:
<?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;

const E_ERROR = 45;
function strlen($str)
{
    return \strlen($str) - 1;
}

echo E_ERROR, "\n"; // 输出 "45"
echo INI_ALL, "\n"; // 输出 "7" - 使用全局常量 INI_ALL

echo strlen('hi'), "\n"; // 输出 "1"
if (is_array('hi')) { // 输出 "is not array"
    echo "is array\n";
} else {
    echo "is not array\n";
}
?>
本作品采用《CC 协议》,转载必须注明作者和本文链接
六月的风
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!