3

我正在尝试将我的 PHP __autoload 函数定义为尽可能防弹和灵活。

这是我的应用程序结构的细分:

/dev (root)
    /my_app
        /php
            /classes
                - Class1.php
                - Class2.php
                - Class3.php
        /scripts
            myscript.php (the file I have to include the classes in)

这是相当直截了当的。我的问题是:我如何编写我的 __autoload 函数,以便我可以包含我想要的任何类,而不管调用文件在目录结构中的嵌套有多深。我知道它与__FILE__,realpathdirname函数有关,但我不确定将它们组合起来以实现我所追求的灵活性的适当方式。

这是我做的一个快速测试:

<?php
echo realpath(dirname(__FILE__)) . "/php/classes/Class1.php";
?>

结果:

/home/mydirectory/dev.mysite.com/my_app/php/scripts/php/classes/Class1.php

如您所见,结果与类所在的位置不匹配。但是,如果我将 myscript.php 文件移动到 /my_app 文件夹中,它将正确打印。

使这更灵活的建议?

4

4 回答 4

3

我建议调查一下spl_autoload。只需将正确的目录添加到您的include_path

这样的事情可能会帮助您入门:

ini_set($your_class_dir_here .PATH_SEPERATOR. ini_get('include_path'));

您必须使用spl_autoload_register或小写所有文件名来提供自己的自动加载器。

这是我自己的自动加载器之一,它使用 php 命名空间来克服一些目录问题。

<?php

namespace Red
{
    // since we don't have the Object yet as we load this file, this is the only place where this needs to be done.
    require_once 'Object.php';

    /**
     * Loader implements a rudimentary autoloader stack.
     */
    class Loader extends Object
    {
        /**
         * @var Loader 
         */
        static protected $instance = null;

        /**
         * @var string 
         */
        protected $basePath;

        /**
         * @return Loader
         */
        static public function instance()
        {
            if (self::$instance == null)
            {
                self::$instance = new self();
            }
            return self::$instance;
        }

        /**
         * Initialize the autoloader. Future expansions to the 
         * autoloader stack should be registered in here.
         */
        static public function Init()
        {
            spl_autoload_register(array(self::instance(), 'autoLoadInNamespace'));
        }

        /**
         * PHP calls this method when a class is used that has not been
         * defined yet. 
         * 
         * I'm returning a boolean for success which isn't required (php ignores it)
         * but makes life easier when the stack grows.
         * 
         * @param string $fullyQualifiedClassName
         * @return boolean 
         */
        public function autoLoadInNamespace($fullyQualifiedClassName)
        {
            $pathParts = preg_split('/\\\\/', $fullyQualifiedClassName, -1, PREG_SPLIT_NO_EMPTY);
            array_unshift($pathParts, $this->basePath);
            $pathToFile = implode(DIRECTORY_SEPARATOR, $pathParts) . '.php';

            if (file_exists($pathToFile))
            {
                require_once $pathToFile;
                return true;
            }
            return false;
        }

        /**
         * Constructor is protected because we don't want multiple instances
         * But we do want an instance to talk to later on.
         */
        protected function __construct()
        {
            $this->basePath = realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..');
        }
    }
}

#EOF;

Loader它是在命名空间中命名的类的一部分,\Red并从一个简单的引导文件初始化:

<?php
// This is where the magic is prepared. 
require_once implode(DIRECTORY_SEPARATOR, array(dirname(__FILE__), 'Red', 'Loader.php'));
// Initialize the autoloader, no more require_once for every class
// and everything is OOP from here on in.
Red\Loader::Init();

#EOF
于 2010-07-17T21:15:03.530 回答
1

我不会选择自动文件位置检测。除非经过深思熟虑它可能是一个安全漏洞,否则您需要设计一个支持子目录的命名示意图,并且它会强制您每个类使用一个文件(这可能是好事也可能是坏事,但我觉得它不灵活)。我会使用一个全局或静态数组,在其中保留一个映射 className => pathToClass。

于 2010-07-17T21:15:11.143 回答
1

$_SERVER['DOCUMENT_ROOT']应包含 Web 服务器根目录的完整路径。从那里您应该能够继续通过文件夹结构到类目录的路径。如果您将应用程序名称存储在会话中,则几乎可以在任何地方使用相同的代码。

//set in config file
if(!isset($_SESSION['APP_DIR'])) $_SESSION['APP_DIR'] = "my_app";

//autoload
//builds a string with document root/app_name/classes
//takes the app name and replaces anything not alphanumeric or _ with an _ and
//makes it lowercase in case of case sensitive. as long as you follow this naming
//scheme for app directories it should be fine for multiple apps.
$classPath = $_SERVER['DOCUMENT_ROOT'] . '/' .
           strtolower(preg_replace('/\W+/', '_', $_SESSION['APP_DIR'])) .
           '/classes/';
于 2010-07-17T21:30:10.410 回答
0

基本上有两种方式。您可以指定类目录的完整绝对路径 ( /home/mydirectory/dev.mysite.com/my_app/php/classes/),我不建议这样做,因为如果您更改主机,它会涉及更改绝对路径。或者您可以使用相对路径,这更容易和可移植:

require_once '../classes/'.$classname;

无需到realpath这里,PHP 可以使用相对路径。;)

PS:realpath(dirname(__FILE__))我认为是重复的。__FILE__已经是“真实路径”,因此您无需调用realpath.

于 2010-07-17T21:03:48.540 回答