自动加载和多个目录

12 php autoload

我一直在看php的autoload()函数.似乎是一个好主意,但我不确定它如何处理多个目录.我当前的开发基本上有一个库目录结构,通过操作将类分组到子目录中.我想知道我必须为每个目录声明一个include()...我真的希望我不必这样做.

你能告诉 - 谢谢

Pas*_*TIN 17

您可能需要查看PEAR约会的类名,这对于自动加载非常有用.

基本上,它声明:

PEAR类层次结构也反映在类名中,层次结构的每个级别用单个下划线分隔.

这意味着找到要包含在classe名称中的文件HTML_Upload_Error只需要用'/'替换'_'; 给你HTML/Upload/Error.php

有关更多说明和几个示例,您可以查看文章:

BTW:这个约定被很多大型框架/库使用;-)
例如,Zend Framework使用这个约定 - 它真的很有帮助!

  • 给出了非常好的解释__autoload的精彩解释链接+1:http://blog.straylightrun.net/2009/05/06/autoload-magic/ (2认同)

Zed*_*Zed 10

这是我前一段时间为了类似目的写的课程.那个时候我还处于学习阶段,所以可能会有愚蠢的想法; 尽管如此.

它的基本思想是扫描源目录一次,并创建一个数组映射类到其源文件.该类被注册为自动加载器,并在调用时包含所需的文件.如果未找到,它会尝试动态重建阵列.

/* register ClassLoader as class loader */
spl_autoload_register(array(ClassLoader::getInstance(), 'loadClass'));


class ClassLoader {

    private static $SAVE_FILE = 'ClassLoader.save.php';

    /* singleton */
    private static $instance;

    /* stores a className -> filePath map */
    private $classList;
    /* tells whether working from saved file */
    private $refreshed;


    public static function getInstance() {
        if (!isset(self::$instance)) {
            self::$instance = new ClassLoader();
        }
        return self::$instance;
    }

    private function __construct() {
        $this->initClassList();
    }

    public function loadClass($className) {
        if ( !array_key_exists($className, $this->classList) && !$this->refreshed ) {
            $this->refreshClassList();
        }
        require_once($this->classList[$className]);
    }

    private function initClassList() {
        if (file_exists(INCLUDES_DIR . self::$SAVE_FILE)) {
            require_once(INCLUDES_DIR . self::$SAVE_FILE);
            $this->refreshed = FALSE;
        } else {
            $this->refreshClassList();
        } 
    }

    private function refreshClassList() {
        $this->classList = $this->scanDirectory(INCLUDES_DIR);
        $this->refreshed = TRUE;

        $this->saveClassList();
    }

    private function saveClassList() {
        $handle = fopen(INCLUDES_DIR . self::$SAVE_FILE, 'w');
        fwrite($handle, "<?php\r\n");

        foreach($this->classList as $class => $path) {
            $line = '$this->classList' . "['" . $class . "'] = '" . $path . "';\r\n";
            fwrite($handle, $line);
        }

        fwrite($handle, '?>');
        fclose($handle);
    }

    private function scanDirectory ($directory) {
        // strip closing '/'
        if (substr($directory, -1) == '/') {
            $directory = substr($directory, 0, -1);
        }

        if (!file_exists($directory) || !is_dir($directory) || !is_readable($directory)) {
            return array();
        }

        $dirH = opendir($directory);
        $scanRes = array();

        while(($file = readdir($dirH)) !== FALSE) {

            // skip pointers
            if ( strcmp($file , '.') == 0 || strcmp($file , '..') == 0) {
                continue;
            }

            $path = $directory . '/' . $file;

            if (!is_readable($path)) {
                continue;
            }

            // recursion
            if (is_dir($path)) {
                $scanRes = array_merge($scanRes, $this->scanDirectory($path));

            } elseif (is_file($path)) {
                $className = explode('.', $file);
                if ( strcmp($className[1], 'class') == 0 && strcmp($className[2], 'php') == 0 ) {
                    $scanRes[$className[0]] = $path; 
                }
            }
        }

        return $scanRes;
    }

}
Run Code Online (Sandbox Code Playgroud)


Luc*_*man 1

不幸的是,您必须显式添加每个目录。这可以在递归遍历目录的脚本中以编程方式完成,也可以指定一个列表。

也许最有效的方法是指定要搜索的目录和子目录列表,并使用 ini_set() 将它们添加到“include_path”中。