【问题标题】:PHP 5.3 autoloaderPHP 5.3 自动加载器
【发布时间】:2012-11-06 15:39:44
【问题描述】:

我想使用 PSR-0 标准的方式来自动加载类而不需要添加包含,例如如何用自动加载机制替换下面的代码:

namespace Example;
use MyLib\Controller;
include_once './library/MyLib/Controller/AbstractController.php';
class MyController extends Controller\AbstractController {
[...]

所以在上面的例子中,它表明在每个控制器中我都需要包含抽象控制器,这太疯狂了......

我在这里找到了 PSR-0 代码:

https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md

https://gist.github.com/221634

但我不知道如何在我的应用程序中实现它。

【问题讨论】:

标签: php autoload psr-0


【解决方案1】:

您需要在应用程序的第一个脚本中包含(包含/要求语句)带有自动加载器代码的文件

如果你像@Skpd 所说的那样选择使用 Composer 的自动加载器,那么你应该在你的第一个 PHP 脚本的顶部有这样的代码。

include_once __DIR__ . '/composer_autoloader.php'

$loader = new \Composer\Autoload\ClassLoader();
$loader->add('MyLib', __DIR__.'/library/');
$loader->register();

如果您决定使用 Composer 作为您的供应商经理,请将您的自定义命名空间添加到您的 composer.json 并包括 vendor/autoload.php

【讨论】:

    【解决方案2】:

    您需要使用自动加载器。有来自 Composer 的示例类加载器:

    <?php
    
    /*
     * This file is part of Composer.
     *
     * (c) Nils Adermann <naderman@naderman.de>
     *     Jordi Boggiano <j.boggiano@seld.be>
     *
     * For the full copyright and license information, please view the LICENSE
     * file that was distributed with this source code.
     */
    
    namespace Composer\Autoload;
    
    /**
     * ClassLoader implements a PSR-0 class loader
     *
     * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
     *
     *     $loader = new \Composer\Autoload\ClassLoader();
     *
     *     // register classes with namespaces
     *     $loader->add('Symfony\Component', __DIR__.'/component');
     *     $loader->add('Symfony',           __DIR__.'/framework');
     *
     *     // activate the autoloader
     *     $loader->register();
     *
     *     // to enable searching the include path (eg. for PEAR packages)
     *     $loader->setUseIncludePath(true);
     *
     * In this example, if you try to use a class in the Symfony\Component
     * namespace or one of its children (Symfony\Component\Console for instance),
     * the autoloader will first look for the class under the component/
     * directory, and it will then fallback to the framework/ directory if not
     * found before giving up.
     *
     * This class is loosely based on the Symfony UniversalClassLoader.
     *
     * @author Fabien Potencier <fabien@symfony.com>
     * @author Jordi Boggiano <j.boggiano@seld.be>
     */
    class ClassLoader
    {
        private $prefixes = array();
        private $fallbackDirs = array();
        private $useIncludePath = false;
        private $classMap = array();
    
        public function getPrefixes()
        {
            return $this->prefixes;
        }
    
        public function getFallbackDirs()
        {
            return $this->fallbackDirs;
        }
    
        public function getClassMap()
        {
            return $this->classMap;
        }
    
        /**
         * @param array $classMap Class to filename map
         */
        public function addClassMap(array $classMap)
        {
            if ($this->classMap) {
                $this->classMap = array_merge($this->classMap, $classMap);
            } else {
                $this->classMap = $classMap;
            }
        }
    
        /**
         * Registers a set of classes
         *
         * @param string       $prefix The classes prefix
         * @param array|string $paths  The location(s) of the classes
         */
        public function add($prefix, $paths)
        {
            if (!$prefix) {
                foreach ((array) $paths as $path) {
                    $this->fallbackDirs[] = $path;
                }
    
                return;
            }
            if (isset($this->prefixes[$prefix])) {
                $this->prefixes[$prefix] = array_merge(
                    $this->prefixes[$prefix],
                    (array) $paths
                );
            } else {
                $this->prefixes[$prefix] = (array) $paths;
            }
        }
    
        /**
         * Turns on searching the include path for class files.
         *
         * @param bool $useIncludePath
         */
        public function setUseIncludePath($useIncludePath)
        {
            $this->useIncludePath = $useIncludePath;
        }
    
        /**
         * Can be used to check if the autoloader uses the include path to check
         * for classes.
         *
         * @return bool
         */
        public function getUseIncludePath()
        {
            return $this->useIncludePath;
        }
    
        /**
         * Registers this instance as an autoloader.
         *
         * @param bool $prepend Whether to prepend the autoloader or not
         */
        public function register($prepend = false)
        {
            spl_autoload_register(array($this, 'loadClass'), true, $prepend);
        }
    
        /**
         * Unregisters this instance as an autoloader.
         */
        public function unregister()
        {
            spl_autoload_unregister(array($this, 'loadClass'));
        }
    
        /**
         * Loads the given class or interface.
         *
         * @param  string    $class The name of the class
         * @return bool|null True, if loaded
         */
        public function loadClass($class)
        {
            if ($file = $this->findFile($class)) {
                include $file;
    
                return true;
            }
        }
    
        /**
         * Finds the path to the file where the class is defined.
         *
         * @param string $class The name of the class
         *
         * @return string|null The path, if found
         */
        public function findFile($class)
        {
            if ('\\' == $class[0]) {
                $class = substr($class, 1);
            }
    
            if (isset($this->classMap[$class])) {
                return $this->classMap[$class];
            }
    
            if (false !== $pos = strrpos($class, '\\')) {
                // namespaced class name
                $classPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)) . DIRECTORY_SEPARATOR;
                $className = substr($class, $pos + 1);
            } else {
                // PEAR-like class name
                $classPath = null;
                $className = $class;
            }
    
            $classPath .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
    
            foreach ($this->prefixes as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
                            return $dir . DIRECTORY_SEPARATOR . $classPath;
                        }
                    }
                }
            }
    
            foreach ($this->fallbackDirs as $dir) {
                if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
                    return $dir . DIRECTORY_SEPARATOR . $classPath;
                }
            }
    
            if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
                return $file;
            }
    
            return $this->classMap[$class] = false;
        }
    }
    

    【讨论】:

    • 已经有很好的自动加载器链接,这里的问题是 OP 不知道如何使用它以及如何正确设置目录结构以与 psr-0 自动加载器一起使用。
    猜你喜欢
    • 2011-09-13
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-26
    • 2017-10-08
    • 1970-01-01
    相关资源
    最近更新 更多