PHP - 最轻量级的符合PSR-0标准的自动加载器

19

我有一个小应用程序需要自动加载器。我可以轻松地使用Symfony2类加载器,但似乎过于复杂。

是否有一个稳定的极其轻量级的PSR-0自动加载器?

7个回答

28
你要求非常轻量级,好的,我们这样做;)
Timothy Boronczyk编写了一个不错的最小SPL自动加载器:http://zaemis.blogspot.fr/2012/05/writing-minimal-psr-0-autoloader.html 我将代码压缩成这样:
function autoload1( $class ) {
    preg_match('/^(.+)?([^\\\\]+)$/U', ltrim( $class, '\\' ), $match ) );
    require str_replace( '\\', '/', $match[ 1 ] )
        . str_replace( [ '\\', '_' ], '/', $match[ 2 ] )
        . '.php';
}

然后将(经缩小的)此[autoload3]与short @Alix Axel code[autoload4]进行比较:

function autoload3($c){preg_match('/^(.+)?([^\\\\]+)$/U',ltrim($c,'\\'),$m);require str_replace('\\','/',$m[1]).str_replace(['\\','_'],'/',$m[2]).'.php';}
function autoload4($c){require (($n=strrpos($c=ltrim($c,'\\'),'\\'))!==false?str_replace('\\','/',substr($c,0,++$n)):null).str_replace('_','/',substr($c,$n)).'.php';}

autoload3是最短的!

让我们使用稳定且极轻巧(175b!)的自动加载器文件:

<?php spl_autoload_register(function ($c){preg_match('/^(.+)?([^\\\\]+)$/U',ltrim($c,'\\'),$m);require str_replace('\\','/',$m[1]).str_replace(['\\','_'],'/',$m[2]).'.php';});
也许我有点疯狂,但你要求的是极端的,对吧? 编辑:感谢Alix Axel,我已经缩短了代码(只有100b!)并使用了include代替require,以防旧库有各种自动加载策略(然后在spl autoload堆栈中有各种自动加载程序...)。
<?php spl_autoload_register(function($c){@include preg_replace('#\\\|_(?!.+\\\)#','/',$c).'.php';});

如果您想让它更短/更好,请使用这个代码片段


4
+1,我没有尝试过,但我认为如果你使用preg_replace()代替preg_match() + str_replace(),你的版本甚至可以更短。 - Alix Axel
1
我并不完全确定preg_match()比其他等效的PHP选项更快。 - TCB13

15

PSR-0规范文档中已经有了一个兼容的自动加载函数示例,而且它已经相当简短:

function autoload($className)
{
    $className = ltrim($className, '\\');
    $fileName  = '';
    $namespace = '';
    if ($lastNsPos = strripos($className, '\\')) {
        $namespace = substr($className, 0, $lastNsPos);
        $className = substr($className, $lastNsPos + 1);
        $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
    }
    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

    require $fileName;
}

使用方法相当简单:

spl_autoload_register('autoload');

这种方法的缺陷在于,你需要通过include_path指令配置它所作用的基目录。为了支持基于SPL语义的混合PSR-0自动加载器,以下代码支持包含路径和spl自动加载扩展:

$spl_autoload_register_psr0 = function ($extensions = null) 
{
    $callback = function ($className, $extensions = null) 
    {
        if (!preg_match('~^[a-z0-9\\_]{2,}$~i', $className)) {
            return;
        }
        null !== $extensions || $extensions = spl_autoload_extensions();
        $extensions = array_map('trim', explode(',', $extensions));
        $dirs = array_map('realpath', explode(PATH_SEPARATOR, get_include_path()));

        $classStub = strtr($className, array('_' => '/', '\\' => '/'));

        foreach ($dirs as $dir) {
            foreach ($extensions as $extension) {
                $file = sprintf('%s/%s%s', $dir, $classStub, $extension);
                if (!is_readable($file)) {
                    continue;
                }
                include $file;
                return;
            }
        }
    };

    return spl_autoload_register($callback);
};

Symfony2 ClassLoader组件的好处在于允许在此处进行更多配置。您可以通过Pear或Composer (Packagist上的symfony/class-loader)轻松安装它。这是一个独立的组件,被许多人使用并且经过了很好的测试和支持。


PSR-0自动加载器的示例,接受扩展并在标准PHP包含路径上工作:http://chat.stackoverflow.com/transcript/message/9066049#9066049 - hakre

10

14
这并不完全符合我所称的“轻量级”。 - cweiske

4

@hakre 提供的答案 的精确等价物,只是更短:

function autoload($class) {
  $path = null;

  if (($namespace = strrpos($class = ltrim($class, '\\'), '\\')) !== false) {
    $path .= strtr(substr($class, 0, ++$namespace), '\\', '/');
  }

  require($path . strtr(substr($class, $namespace), '_', '/') . '.php');
}

你可以通过更改$path = null;的值来设置基目录,或者像这样操作:
$paths = array
(
    __DIR__ . '/vendor/',
    __DIR__ . '/vendor/phunction/phunction.php',
);

foreach ($paths as $path)
{
    if (is_dir($path) === true)
    {
        spl_autoload_register(function ($class) use ($path)
        {
            if (($namespace = strrpos($class = ltrim($class, '\\'), '\\')) !== false)
            {
                $path .= strtr(substr($class, 0, ++$namespace), '\\', '/');
            }

            require($path . strtr(substr($class, $namespace), '_', '/') . '.php');
        });
    }

    else if (is_file($path) === true)
    {
        require($path);
    }
}

1

0

这不是对问题的直接回答,但我发现上面的答案在独立的PHP脚本中效果很好,但在某些框架(如Joomla)中使用时会出现问题。

对于任何使用Joomla的人来说,事实证明该框架已经内置了兼容的自动加载程序,因此您不需要使用上述函数。在这种情况下,只需调用JLoader::registerNamespace()即可...例如:

JLoader::registerNamespace('Solarium', JPATH_LIBRARIES . DS . 'solarium-3.2.0' . DS . 'library');

0
function autoload($fullClassName) {
    $name_elems = explode('\\', $fullClassName);
    require __DIR__.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $name_elems).'.php';
}

这甚至支持像这样的东西: $ transformerContstraint = new \ Recurr \ Transformer \ Constraint \ AfterConstraint(new DateTime());

只需将其放入/vendor/Recurr/Transformer/Constraint/AfterConstraint.php中即可


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接