从最简单的开始。

当文件都在同一个目录时

新建一个文件Application.php,内容如下:

<?php 
namespace PPP;
class Application{
    public function world()
    {
        echo "hello";
    }
}

Application.php文件的命名空间是PPP
在同目录下再新建一个文件hello.php,内容如下:

<?php
//------------------------
// php 服务器500错误解决
// 开启php.ini中的display_errors指令
ini_set('display_errors',1);
// 通过error_reporting()函数设置,输出所有级别的错误报告
error_reporting(E_ALL);
//------------------------

use PPP\Application;
$hk = new Application;
var_dump($hk);

在没有require或者include的情况下,仅仅使用use关键字是无法正常实例化Application对象的,因为use只是逻辑上的引用。PHP不知道PPP\Application实际的物理位置。
现在添加require

<?php
//------------------------
// php 服务器500错误解决
// 开启php.ini中的display_errors指令
ini_set('display_errors',1);
// 通过error_reporting()函数设置,输出所有级别的错误报告
error_reporting(E_ALL);
//------------------------

require_once __DIR__ . "/Application.php";
use PPP\Application;
$hk = new Application;
var_dump($hk);

现在程序能正常运行了。

现在在当前目录下创建一个文件夹PPP,并把Application.php文件放到PPP目录,这时候就需要重新更改require的路径了。

<?php
//------------------------
// php 服务器500错误解决
// 开启php.ini中的display_errors指令
ini_set('display_errors',1);
// 通过error_reporting()函数设置,输出所有级别的错误报告
error_reporting(E_ALL);
//------------------------

require_once __DIR__ . "/PPP/Application.php";
use PPP\Application;
$hk = new Application;
var_dump($hk);

还可以使用spl_autoload_register()和命名空间

<?php
//------------------------
// php 服务器500错误解决
// 开启php.ini中的display_errors指令
ini_set('display_errors',1);
// 通过error_reporting()函数设置,输出所有级别的错误报告
error_reporting(E_ALL);
//------------------------

spl_autoload_register();
use PPP\Application;
$hk = new Application;
var_dump($hk);

但是使用spl_autoload_register()的话,文件的名称与路径要严格和namespace命名空间一致。当Application文件所在的目录不是PPP时就会发生错误。

但是这些都是发生在运行的hello.php文件所在的目录下的,包括PPP目录也是和hello.php在同一个目录的。

如果我们把PPP目录放到其他地方,上面的代码就又失效了。

当文件在不同目录时

在继续之前,要先了解PHP中获取路径的方法

echo __FILE__ ; // 获取当前所在文件的绝对路径及地址,结果:D:\aaa\my.php 
echo dirname(__FILE__); // 取得当前文件所在的绝对目录,结果:D:\aaa\ 
echo dirname(dirname(__FILE__)); //取得当前文件的上一层目录名,结果:D:\ 

知道了PHP如何获取路径后,我们定义以下的目录结构:

/root/
 |
 |---/PHP_Object/
 |       |
 |       |----hello.php
 |
 |---/PPP/
 |     |
 |     |----Application.php
 |
 |---/test/
 |     |
 |     |----/aaa/
 |           |
 |           |----Blao.php
 |

三个文件在不同的目录。先来看Application.php文件

<?php 
namespace root\PPP;
class Application{
    public function world()
    {
        echo "hello world";
    }
}

namespace命名空间对应实际文件位置root\PPP

spl_autoload_register()还可以接受一个参数,但是这个参数是匿名函数

hello.php文件

<?php
$namespaces = function ($path){
    if(preg_match('/\\\\/',$path))
    {
        $path = str_replace('\\',DIRECTORY_SEPARATOR,$path);
    }    
    $path = dirname(dirname(dirname(__FILE__))) . "/" . "$path"; 
    //var_dump($path);
    if(file_exists("{$path}.php"))
    {
        require_once("{$path}.php");
    }
};

\spl_autoload_register($namespaces);

$blah = new root\PPP\Application();
$blah->world();
echo "<br/>";
$www = new root\test\aaa\Blao();
$www->nd();

上面的代码中,先定义了一个匿名参数,这个匿名参数的作用是将namesapce命名空间中的反斜杠(\)替换为路径斜杠(/),dirname(dirname(dirname(__FILE__)))这里得到的就是当前目录的上级目录,也就是root目录。

当PHP引擎要实例化Application类时,就会运行spl_autoload_register()去自动加载需要的类文件,对于Blao类也是同理。


参考资料:
php不同路径的类文件自动加载
关于 PHP 命名空间的一个疑问
《深入PHP·面向对象、模式与实践》5.1.2 自动加载

标签: none

评论已关闭