【问题标题】:php autoloader: why does this work?php autoloader:为什么会这样?
【发布时间】:2013-07-22 19:41:51
【问题描述】:

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

这是工作代码:

<?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;
            }
        }
    }
?>

这是一个我觉得应该工作的sn-p,但没有:

<?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');
    }
?>

“没有这样的文件或目录...”错误让我觉得我可以简单地检查一个类的支持文件,如果 (file_exists()) {require_once();休息;}否则{继续;}

为什么这不起作用?而且,为什么第一个 sn-p 有效?支持路径/文件从未明确包含或要求。

【问题讨论】:

  • 是你include_paths中classes路径的父目录吗?
  • 包含支持文件,只是合并到if语句中: if (!@include_once($location . $class . '.php'))
  • 是的,我有点想,john500,但希望得到确认,所以谢谢你。不过,这感觉像是一种非常草率的方式来实现我所需要的,所以这只会让我更加渴望改进解决方案。 Orangepill,我不知道该怎么做...我已经有一段时间没有使用 PHP 了,当我上次使用 PHP 时,我的编程能力还没有现在的一半...所以我基本上是在 PHP 上尝试做一些我已经知道如何在 Java 和 ColdFusion 中做的事情;)。
  • 抱歉,我失去了编辑最后一篇文章的能力,而且它有太多绒毛...... Orangepill,我应该说,我不确定如何利用 include_path 来解决这个问题,但我肯定认为我错误地引用了 /classes 目录。它不在根目录下,而我正在处理的站点位于子目录中,我有点/有点认为我没有以编程方式构建正确的路径。

标签: php spl-autoloader


【解决方案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__ 返回调用它的实际文件的目录位置(而不是包含它的文件),这意味着只要该文件保留在目录的根目录与我的 /classes 目录。而且,它专门用于定义这些类型的设置...

希望这对其他人有所帮助!而且,当然,如果有人能解释为什么这个解决方案是次优的,我会全神贯注......

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

EDIT2:如果有人感兴趣,这里是我想出的作为关联数组执行此操作的解决方案。基本上,我在 $GLOBALS 中设置了一个关联数组,并使用它来存储 Classes -> Packages 的映射。然后,在自动加载器中,我映射 Packages -> Locations,然后调用实例化类所需的文件。

这是全局配置文件:

<?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,但我听到的评价褒贬不一……

【讨论】:

  • PHP 5.3 起也可以使用__DIR__
猜你喜欢
  • 2015-12-23
  • 2018-10-15
  • 2015-06-19
  • 2012-07-08
  • 2022-12-18
  • 2011-06-03
  • 2018-06-08
  • 2014-12-21
相关资源
最近更新 更多