命名空间之spl_autoload_register

79 阅读1分钟
1 文件目录如下:
.
├── main.php
└── tt
    └── aa
        └── Animal.php

2 其中 main.php 如下:
<?php
error_reporting(E_ALL);

function getPath($className) {
    $className = ltrim($className, '\\');
    var_dump($className);
    $fileName  = '';
    $namespace = '';
    if ($lastNsPos = strrpos($className, '\\')) {
        $namespace = substr($className, 0, $lastNsPos);
        var_dump($namespace);
        $className = substr($className, $lastNsPos + 1);
        var_dump($className);
        $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
        var_dump($fileName);
    }
    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
    var_dump($fileName);
    return $fileName;
}


function load($classname){

    echo implode(' | ', array(__FILE__,__FUNCTION__,__LINE__,"\n"));
    var_dump($classname);

    $classpath = getPath($classname);


   if(file_exists($classpath)){
       require_once($classpath);
   }else{
       echo $classpath." not be found!";
   }
}

spl_autoload_register('load');

$ani = new \tt\aa\Animal();
echo implode(' | ', array(__FILE__,__FUNCTION__,__LINE__,"\n"));



3 Animal.php如下:
<?php
namespace tt\aa;

class Animal{
    public function __construct(){
        echo implode(' | ', array(__FILE__,__FUNCTION__,__LINE__,"\n"));
    }
}


4 输出如下:
[dev@dev02 t2]$ php main.php
/home/dev/git/test/t2/main.php | load | 25 |
string(12) "tt\\aa\\Animal"
string(12) "tt\\aa\\Animal"
string(5) "tt\\aa"
string(6) "Animal"
string(6) "tt/aa/"
string(16) "tt/aa/Animal.php"
/home/dev/git/test/t2/tt/aa/Animal.php | __construct | 6 |
/home/dev/git/test/t2/main.php |  | 41 |

如果main.php调用load方法是放在new之后

$ani = new \tt\aa\Animal();
spl_autoload_register('load');
echo implode(' | ', array(__FILE__,__FUNCTION__,__LINE__,"\n"));

php就会报错:

==> /apps/logs/php_error.log <==
[01-Apr-2019 17:28:04 Asia/Shanghai] PHP Fatal error:  Class 'tt\aa\Animal' not found in /home/dev/git/test/t2/main.php on line 39
[01-Apr-2019 17:28:04 Asia/Shanghai] PHP Stack trace:
[01-Apr-2019 17:28:04 Asia/Shanghai] PHP   1. {main}() /home/dev/git/test/t2/main.php:0

spl_autoload_register方法必须在new之前就调用。 其实spl_autoload_register方法注册引入函数,当新建对象,如果本class文件找不到,则会调用spl_autoload_register中注册的函数,最后看能否找到。

找到了就会把参数 $classname,从 \\ 转成目录 / ,最终使用require来加载到内存中。

spl_autoload_register 可以注册多个。 __autoload只能有一个。

注册__autoload函数,只是注册一个加载函数.这个修改了php底层的加载模式.为了不修改底层的加载模式,php提出一种新的加载方式,spl_autoload_register.这个是一个函数队列,如果理解队列呢.就是从上往下找,直到找到为止.具体的来说,就是

* __autoload会改变底层的加载模式,而spl_autoload_register不会.
* spl_autoload_register是一个加载队列,如果需要多条 autoload 函数,spl_autoload_register满足了此类需求

开发中用到的一般是用spl_autoload_register。

参考资料:segmentfault.com/q/101000001…