php程序员PHP经验分享

《Thinkphp5入门系列课程》第三课:命名空间

2017-08-29  本文已影响268人  6aec4f6b9d46

命名空间

什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。具体举个例子,文件 foo.txt 可以同时在目录 /home/greg/home/other 中存在,但在同一个目录中不能存在两个 foo.txt 文件。另外,在目录 /home/greg 外访问 foo.txt 文件时,我们必须将目录名以及目录分隔符放在文件名之前得到 /home/greg/foo.txt 。这个原理应用到程序设计领域就是命名空间的概念。

上面描述来自:php手册:命名空间概述

从上面的解释中我们可以清晰的看到,命名空间主要的作用就是方便管理类!就如下面的例子一样:当没有命名空间的时候,如果我们用下面的定义:

<?php
class Demo {
  public function one ()
  {
    echo __METHOD__;
  }
}

class Demo {
  public function two ()
  {
    echo __METHOD__;
  }
}

运行结果:

PHP Fatal error:  Cannot redeclare class Demo

会直接报错的,因为类名相同导致冲突了。但是如果引入命名空间的话,就可以很方便的解决此冲突问题:

<?php
namespace One;
class Demo {
  public function one ()
  {
    echo __METHOD__;
  }
}

namespace Two;
class Demo {
  public function two ()
  {
    echo __METHOD__;
  }
}

$demo1 = new \One\Demo();
$demo2 = new \Two\Demo();
$demo1->one();
$demo2->two();

运行结果:

One\Demo::oneTwo\Demo::two

可见命名空间完美的解决了类名冲突的问题。

注意,上面代码只做演示,在实际的编程实践中,非常不提倡在同一个文件中定义多个命名空间。

自动加载

在没有命名空间之前,我们使用所需要的类的时候是这样的:

<?php
require_once 'glass/demo.php';
require_once 'glass/demo1.php';
require_once 'glass/demo2.php';

$demo = new Demo();
$demo1 = new Demo1();
$demo2 = new Demo2();

有了命名空间之后,我们使用类是这样的:

<?php
require_once 'autoload.php';

$demo = new Demo();
$demo1 = new Demo1();
$demo2 = new Demo2();

可以明显看到,第一种方法有以下缺点:

反观第二种方法,全自动加载,不需要手动 require_once ;不需要知道类完整的路径!你说,哪一种使用方便呢?^ - ^.

__autoload() 函数

void __autoload ( string $class )

该函数的主要作用是在 PHP 运行中如果类未加载就会触发这个函数,PHP 会将未加载类的类名(包括命名空间)作为 __autoload 函数的第一个参数传递进来并执行函数。而 __autoload 函数就是的主要责任就是通过类名(包括命名空间)来加载这个类!

你可以通过定义这个函数来启用类的自动加载。

具体使用方法如下:

首先,在项目中创建 index.php 文件:

<?php
function __autoload ($className)
{
    $filepath = $className . '.php';
    if (!file_exists($filepath)) {
        throw new Exception('FILE NOT FOUND.');
    }
    require_once $filepath;
}

$demo = new Demo();
$demo->echo();

紧接着创建 Demo.php 文件:

<?php
class Demo {
    public function echo ()
    {
        echo __CLASS__;
    }
}

启动 PHP 内置服务器,在命令行运行:

php -S localhost:3000

在浏览器输入 localhost:3000 ,内容如下:

Demo

这样,一个简单的自动加载就完成了。整个过程非常简单:初始化一个未加载的类 -> PHP找不到这个类 -> 触发 __autoload 函数 -> __autoload 根据类型检测并加载当前目录下的类。

spl_autoload_register 函数

bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] )

其主要作用和 __autoload 函数相同,都是用来加载类。不过 spl_autoload_register 函数可以定义多次,而 __autoload 只能定义一次。如果 spl_autoload_register 定义多次,那么在类加载的时候就会按照定义的顺序从上到下执行,一直到找到类或遍历完所有的 spl_autoload_register 为止。

注意:如果使用 spl_autoload_register 那么 __autoload 函数将失效。

参数 解释
autoload_function 欲注册的自动装载函数。
throw 此参数设置了 autoload_function 无法成功注册时, spl_autoload_register()是否抛出异常。
prepend 如果是 true,spl_autoload_register() 会添加函数到队列之首,而不是队列尾部。

来看个 Demo 。就上面的示例代码来说,我们也可以这样写:

index.php

<?php
spl_autoload_register(function ($className) {
    $filepath = $className . '.php';
    if (!file_exists($filepath)) {
        throw new Exception('FILE NOT FOUND.');
    }
    require_once $filepath;
});

$demo = new Demo();
$demo->echo();

命名空间 + 自动加载

且看下面的代码:

<?php
spl_autoload_register(function ($className) {
    var_dump($className);
});

$demo = new \Xiao\Teng\Demo();
$demo->echo();

输出结果如下:

string(14) "Xiao\Teng\Demo" 

可以看到,打印的值中包含了命名空间,此时我们将命名空间与目录映射就可以实现一个基本符合 PSR4 自动加载规范的自动加载啦!具体代码如下:

在项目根目录创建 index.php :

<?php
spl_autoload_register(function ($className) {
    $filepath = str_replace('\\', '/', $className) . '.php';
    if (!file_exists($filepath)) {
        throw new Exception('FILE NOT FOUND.');
    }
    require_once $filepath;
});

$demo = new \Xiao\Teng\Demo();
$demo->echo();

紧接着创建 Xiao/Teng/Demo.php

<?php
namespace Xiao\Teng;
class Demo {
    public function echo ()
    {
        echo __CLASS__;
    }
}

运行结果如下:

Xiao\Teng\Demo

这里要注意两点,第一:命名空间与路径的映射要理清楚;第二:需要加载的类文件的命名空间要填写完整,否则还是提示类无法找到!

此篇为小滕的《Thinkphp5入门系列课程》第三篇。
喜欢的给个订阅呗!

上一篇下一篇

猜你喜欢

热点阅读