web-dev-qa-db-ja.com

PHP-最も軽量なpsr-0準拠のオートローダー

オートローダーが必要な小さなアプリケーションがあります。 symfony2クラスローダーは簡単に使用できましたが、やり過ぎのようです。

安定した非常に軽量なpsr-0オートローダーはありますか?

19
Marty Wallace

あなたは非常に軽量であると尋ねます、そうしましょう;)

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](の縮小バージョン)を 短い@Alix Axelコード [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';});

多分私は夢中ですが、あなたは極端なことを求めましたね?

EDIT:Alix Axelのおかげで、コードを短縮し(100bのみ!)、さまざまなオートロード戦略がある場合に備えて、requireの代わりにincludeを使用しました。古いライブラリ(そしてsplオートロードスタックのさまざまなオートローダー...)。

<?php spl_autoload_register(function($c){@include preg_replace('#\\\|_(?!.+\\\)#','/',$c).'.php';});

短く/良くしたい場合は、これを使用してください 要点

28
Adrien Gibrat

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オートローダーをサポートするために、次の1つはincludepathおよびsplautoload拡張をサポートします。

$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 )を介して簡単にインストールできます。これはそれ自体のコンポーネントであり、多くの人がかなりよく使用しています。テストおよびサポートされています。

15
hakre

SplClassLoader は正しい選択のようです。これは実装です PSR-0によって提案されました それ自体。

10
Crozin

@ 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);
    }
}
4
Alix Axel

doctrine classloader も良い選択です。 composer で簡単にインストールできます

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

これは、次のようなものもサポートします。$ transformerContstraint = new\Recurr\Transformationer\Constraint\AfterConstraint(new DateTime());

/vendor/Recurr/Transformer/Constraint/AfterConstraint.phpに入れるだけです

0
Luke Wenke

これは質問に対する直接の答えではありませんが、上記の答えはスタンドアロンのPHPスクリプトではうまく機能しましたが、Joomlaなどの特定のフレームワークで使用すると問題が発生することがわかりました。

Joomlaを使用している人は、互換性のあるオートローダーがすでにフレームワークに組み込まれていることがわかります。したがって、上記の関数を使用する必要はありません。その場合は、JLoader :: registerNamespace()....を呼び出すだけです。例:

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