php autoloader:为什么这个工作?

时间:2013-07-23 15:59:24

标签: php spl-autoloader

我一直在尝试使用自动加载器类目录映射技术,这有点困难。我设法提出了一个相当直接的解决方案(表面上看),但我完全神秘的是它完全有效,而其他“更明显”的解决方案失败了。下面是一些代码片段,说明了我的困惑。

这是工作代码:

<?php
    spl_autoload_register('my_autoloader');

    function my_autoloader($class) {
        $classMap = array(
            'classes/',
            'classes/sites/',
            'classes/data/'
        );
        foreach ($classMap as $location) {
            if (!@include_once($location . $class . '.php')) { // @ SUPPRESSES include_once WARNINGS
                // CLASS DOESN'T EXIST IN THIS DIRECTORY
                continue;
            } else {
                // CLASS IS AUTO-LOADED
                break;
            }
        }
    }
?>

这是我觉得工作的片段,但不是:

<?php
    spl_autoload_register('my_autoloader');

    function my_autoloader($class) {
        $classMap = array(
            'classes/',
            'classes/sites/',
            'classes/data/'
        );
        foreach ($classMap as $location) {
            if (file_exists($location . $class . '.php')) {
                require_once ($location . $class . '.php');
            }
        }
    }
?>

后者对我更有意义,因为虽然这两个版本有效:

<?php
    spl_autoload_register('my_autoloader');

    function my_autoloader($class) {
        require_once ('classes/sites/' . $class . '.php');
    }
?>

<?php
    spl_autoload_register('my_autoloader');

    function my_autoloader($class) {                
        $location = 'classes/sites/';                
        require_once ($location . $class . '.php');
    }
?>

这个抛出“没有这样的文件或目录......”(注意路径中缺少“sites /”。

<?php
    spl_autoload_register('my_autoloader');

    function my_autoloader($class) {
        require_once ('classes/' . $class . '.php');
    }
?>

“没有这样的文件或目录...”错误让我觉得我可以简单地检查一个类的支持文件,if(file_exists()){require_once(); break;} else {continue;}

为什么不起作用?而且,为什么第一个代码段工作?支持路径/文件从未明确包含或要求。

1 个答案:

答案 0 :(得分:1)

好的,我明白了。我的问题确实没有正确设置路径;使用__DIR__常量是:: ahem ::成功之路。这是我正在使用的工作代码:

<?php
    spl_autoload_register('my_autoloader');

    function my_autoloader($class) {
        $classMap = array(
            'classes/',
            'classes/sites/',
            'classes/data/'
        );
        foreach ($classMap as $location) {
            if (file_exists(__DIR__ . '/' . $location . $class . '.php')) {
                require_once(__DIR__ . '/' . $location . $class . '.php');
                break;
            }
        }
    }
?>

事实证明__DIR__返回调用它的实际文件的目录位置(而不是包含它的文件),这意味着只要此文件仍然存在,这将起作用在my / classes目录的目录根目录中。并且,它仅用于定义这些类型的设置......

希望这有助于其他人下线!而且,当然,如果有人能够阐明为什么这个解决方案不是最优的话,那我只是眼睛......

编辑:我将执行的一个优化是将$ classMap数组()转换为关联数组(例如,$classMap = array('root' => 'classes/', 'sites' => 'classes/sites/');,这样我就可以进行查找而不是循环我创建的所有目录随着时间​​的推移。但是,我想这是另一个线程。

EDIT2 :如果有人感兴趣,这就是我想出的解决方案,作为一个关联数组。基本上,我在$ GLOBALS中设置了一个关联数组,并使用它来存储类的地图 - &gt;包。然后,在自动加载器中,我映射包 - &gt;位置然后调用实例化类所需的文件。

这是全局配置文件:

<?php
    // INITIALIZE GLOBAL Class -> Package map
    if (!array_key_exists('packageMap',$GLOBALS)) {
        $GLOBALS['packageMap'] = array();
    }

    spl_autoload_register('my_autoloader');

    function my_autoloader($class) {
        $classMap = array(
            'root'=>'/classes/',
            'sites'=>'/classes/sites/',
            'data'=>'/classes/data/'
        );

        // RESOLVE MAPPINGS TO AN ACTUAL LOCATION
        $classPackage = $GLOBALS['packageMap'][$class];
        $location = $classMap[$classPackage];
        if (file_exists(__DIR__ . $location . $class . '.php')) {
            require_once(__DIR__ . $location . $class . '.php');
        }
    }
?>

以下是使用自动加载器的特定站点配置文件:

<?php   
    // LOAD GLOBAL CONFIG FILE      
    require_once('../config/init.php');

    // CREATE LOCAL REFERENCE TO GLOBAL PACKAGE MAP (MOSTLY FOR READABILITY)
    $packageMap = $GLOBALS['packageMap'];

    // ADD Class -> Package MAPPINGS
    $packageMap['DAO'] = 'data';
    $packageMap['SomeSite'] = 'sites';
    $packageMap['PDOQuery'] = 'data';

    // INSTANTIATE SOMETHING IN ONE OF THE PACKAGES
    $someSite = new SomeSite();
?>

希望这对其他人有用...如果它为任何人引起任何危险信号,请加入。最终,我想用apc替换$ GLOBALS的使用,但它没有安装在我的托管服务器上: /。我可能会考虑memcached,但我听说过混合评论...