オートロードでPHP名前空間を使用するにはどうすればよいですか?


104

自動ロードと名前空間を使用しようとすると、このエラーが発生します。

致命的なエラー:クラス 'Class1' が行10の/usr/local/www/apache22/data/public/php5.3/test.phpに見つかりません

誰かが私が間違っていることを教えてもらえますか?

これが私のコードです:

Class1.php:

<?php

namespace Person\Barnes\David
{
    class Class1
    {
        public function __construct()
        {
            echo __CLASS__;
        }
    }
}

?>

test.php:

<?php

function __autoload($class)
{
    require $class . '.php';
}

use Person\Barnes\David;

$class = new Class1();

?>

回答:


119

Class1はグローバルスコープにありません。

実際の例については、以下を参照してください。

<?php

function __autoload($class)
{
    $parts = explode('\\', $class);
    require end($parts) . '.php';
}

use Person\Barnes\David as MyPerson;

$class = new MyPerson\Class1();

編集(2009-12-14):

明確にするために、「use ... as」の使用は例を簡略化することでした。

別の方法は次のとおりです。

$class = new Person\Barnes\David\Class1();

または

use Person\Barnes\David\Class1;

// ...

$class = new Class1();

1
を使用する必要はありませんAS。これがこのソリューションが機能する理由ではありません。同じように簡単にできます:(use Person\Barnes\David\Class1;これはと同じですuse Person\Barnes\David\Class1 as Class1;)。
cartbeforehorse 2013年

1
おかげで、これは動作します。しかし、なぜ$ class = new Class1();を使用できるのか理解できません。以前に「use Person \ Barnes \ David;」をすでに定義している場合は、
user345602 14

4
@ user346665を使用use Person\Barnes\David\Class1;するには、使用する必要があります$class = new Class1();。とuse Person\Barnes\David;する必要があります$class = new David\Class1();useそれ自体でキーワードは同等であるuse Person\Barnes\David\Class1 as Class1;又はuse Person\Barnes\David as David;、それぞれ例えば。
ジャスティンC

2018年の記事を読むには、spl_autoload_registerで@ prince-billy-grahamソリューションを使用してください
Bruno de Oliveira

26

Pascal MARTINで述べたように、「\」をDIRECTORY_SEPARATORに置き換える必要があります。次に例を示します。

$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
include($filename);

また、コードを読みやすくするためにディレクトリ構造を再編成することをお勧めします。これは代わりになるかもしれません:

ディレクトリ構造:

ProjectRoot
 |- lib

ファイル: /ProjectRoot/lib/Person/Barnes/David/Class1.php

<?php
namespace Person\Barnes\David
class Class1
{
    public function __construct()
    {
        echo __CLASS__;
    }
}
?>
  • 定義した名前空間ごとにサブディレクトリを作成します。

ファイル: /ProjectRoot/test.php

define('BASE_PATH', realpath(dirname(__FILE__)));
function my_autoloader($class)
{
    $filename = BASE_PATH . '/lib/' . str_replace('\\', '/', $class) . '.php';
    include($filename);
}
spl_autoload_register('my_autoloader');

use Person\Barnes\David as MyPerson;
$class = new MyPerson\Class1();
  • オートローダーの宣言にphp 5の推奨事項を使用しました。まだPHP 4を使用している場合は、古い構文に置き換えます:function __autoload($ class)

18

あなたの__autoload関数は、名前空間名を含む、完全なクラス名を受け取ることになります。

つまり、あなたの場合、__autoload関数は ' Person\Barnes\David\Class1'だけでなく ' Class1' を受け取ります。

したがって、そのような「より複雑な」名前を処理するには、オートローディングコードを変更する必要があります。よく使用される解決策は、名前空間の「レベル」ごとに1レベルのディレクトリを使用してファイルを編成し、オートロード時\に名前空間名の' 'をに置き換えることDIRECTORY_SEPARATORです。


1
これは私が見つけたものではありません。私がステートメントdie($ class);を入れたとき __autoload関数では、「Person \ Barnes \ David \ Class1」ではなく「Class1」を出力しました
David Barnes

そうだね。autoloadの$ classパラメーターは、コンストラクター呼び出しで記述されたクラス名です。
tishma 2013

1
__autoload関数は名前空間名を含む完全なクラス名を受け取る」への反対票-これはuse、参照しようとしているクラスを明示的にdにした場合にのみ当てはまり、use所属する名前空間を単にdにしただけでは当てはまりません。OPの誤りはuse、クラスを含む名前空間を作成し、autoload関数が魔法のように完全なクラスパスをなんとか渡されることを期待していたことでした。この回答は、OPの間違いを実際に解決するものではありません。
Mark Amery 2014年

15

私はこのようなことをします:このGitHubの例を参照してください

spl_autoload_register('AutoLoader');

function AutoLoader($className)
{
    $file = str_replace('\\',DIRECTORY_SEPARATOR,$className);

    require_once 'classes' . DIRECTORY_SEPARATOR . $file . '.php'; 
    //Make your own path, Might need to use Magics like ___DIR___
}

3
素敵でシンプル。それを探す必要がある場合。)
デニス

3

Flysystemからこの宝石を見つけました

spl_autoload_register(function($class) {
    $prefix = 'League\\Flysystem\\';

    if ( ! substr($class, 0, 17) === $prefix) {
        return;
    }

    $class = substr($class, strlen($prefix));
    $location = __DIR__ . 'path/to/flysystem/src/' . str_replace('\\', '/', $class) . '.php';

    if (is_file($location)) {
        require_once($location);
    }
});

3

次の2つのケースでは、オートロード機能が「フル」クラス名のみを受け取り、すべてのネームスペースがその前にあることがわかります。

[a] $a = new The\Full\Namespace\CoolClass();

[b] use The\Full\Namespace as SomeNamespace; (at the top of your source file) followed by $a = new SomeNamespace\CoolClass();

次の場合、オートロード関数が完全なクラス名を受信しないことがわかります。

[c] use The\Full\Namespace; (at the top of your source file) followed by $a = new CoolClass();

更新:[c]は誤りであり、ネームスペースの動作方法ではありません。[c]の代わりに、次の2つのケースもうまく機能すると報告できます。

[d] use The\Full\Namespace; (at the top of your source file) followed by $a = new Namespace\CoolClass();

[e] use The\Full\Namespace\CoolClass; (at the top of your source file) followed by $a = new CoolClass();

お役に立てれば。


ちなみに、このuseキーワードはPHPの対話型コマンドラインインターフェース(php --interactive)では適切に機能しません。
Andrew Larsson

3

この簡単なハックを1行で使用します。

spl_autoload_register(function($name){
        require_once 'lib/'.str_replace('\\','/',$name).'.php';
    });

1

同じ問題があり、これを見つけました:

含まれているクラスの名前空間に一致するサブフォルダー構造を作成するとき、オートローダーを定義する必要さえありません。

    spl_autoload_extensions(".php"); // comma-separated list
    spl_autoload_register();

それは魅力のように働きました

詳細はこちら:http : //www.php.net/manual/en/function.spl-autoload-register.php#92514

編集:これはバックスラッシュのためにLinuxで問題を引き起こします...immeëmosolによる実用的な解決策はここを参照してください

名前空間のオートロードはWindowsでは機能しますが、Linuxでは機能しません


1

を使用すると問題が発生しますが、これは断然最速の方法ですが、すべてのファイル名が小文字であることも想定しています。

spl_autoload_extensions(".php");
spl_autoload_register();

例えば:

SomeSuperClassクラスを含むファイルはsomesuperclass.phpという名前にする必要があります。Linuxのように大文字と小文字を区別するファイルシステムを使用する場合、これはファイルがSomeSuperClass.phpという名前でWindowsでの問題ではない場合の問題です。

コードで__autoloadを使用しても、PHPの現在のバージョンで動作する可能性がありますが、この機能は非推奨となり、将来的には削除される予定です。

したがって、残っているオプションは次のとおりです。

このバージョンはPHP 5.3以降で動作し、SomeSuperClass.phpおよびsomesuperclass.phpというファイル名を使用できます。5.3.2以降を使用している場合、このオートローダーはさらに高速に動作します。

<?php

if ( function_exists ( 'stream_resolve_include_path' ) == false ) {
    function stream_resolve_include_path ( $filename ) {
        $paths = explode ( PATH_SEPARATOR, get_include_path () );
        foreach ( $paths as $path ) {
            $path = realpath ( $path . PATH_SEPARATOR . $filename );
            if ( $path ) {
                return $path;
            }
        }
        return false;
    }
}

spl_autoload_register ( function ( $className, $fileExtensions = null ) {
    $className = str_replace ( '_', '/', $className );
    $className = str_replace ( '\\', '/', $className );
    $file = stream_resolve_include_path ( $className . '.php' );
    if ( $file === false ) {
        $file = stream_resolve_include_path ( strtolower ( $className . '.php' ) );
    }
    if ( $file !== false ) {
        include $file;
        return true;
    }
    return false;
});

2
サイドノートとして、str_replace ([ '_','\\'] '/', $className );二倍の速さよりも2つのstr_replaceである
イタイMoav -Malimovka

phpファイルの大文字と小文字が区別されないかぎり、ディレクトリは大文字と小文字を区別します
Mike

1

最近、tanerkucの回答が非常に参考になりました。ただ、使用していることを追加したいstrrpos()+するsubstr()よりもわずかに速いですexplode()+ end()

spl_autoload_register( function( $class ) {
    $pos = strrpos( $class, '\\' );
    include ( $pos === false ? $class : substr( $class, $pos + 1 ) ).'.php';
});

1

相対的な初心者または単純なspl_autoload_register()のセットアップを必要としないので、理論をすべて使わずに2セントで投入します。クラスごとに1つのphpファイルを作成し、そのphpファイルにクラス名と同じ名前を付け、クラスファイルを保持します。問題のphpファイルと同じディレクトリにある場合、これは機能します:

spl_autoload_register(function ($class_name) {
    require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . $class_name . '.php';
});

この関数内の部分をグーグルすることで、この関数の動作がわかるはずです。PS:私はLinuxを使用していますが、これはLinuxで動作します。Windowsのユーザーは、最初にテストする必要があります。


1

https://thomashunter.name/blog/simple-php-namespace-friendly-autoloader-class/

クラスファイルをという名前のフォルダーに配置しますClasses。このフォルダーは、PHPアプリケーションへのエントリポイントと同じディレクトリにあります。クラスが名前空間を使用する場合、名前空間はディレクトリ構造に変換されます。

他の多くのオートローダーとは異なり、アンダースコアはディレクトリ構造に変換されません(PHP <= 5.3の擬似名前空間をPHP> = 5.3の実際の名前空間とともに実行するのは難しいです)。

<?php
class Autoloader {
    static public function loader($className) {
        $filename = "Classes/" . str_replace("\\", '/', $className) . ".php";
        if (file_exists($filename)) {
            include($filename);
            if (class_exists($className)) {
                return TRUE;
            }
        }
        return FALSE;
    }
}
spl_autoload_register('Autoloader::loader');

次のコードをメインのPHPスクリプトに挿入する必要があります(エントリポイント)。

require_once("Classes/Autoloader.php");

次に、ディレクトリレイアウトの例を示します。

index.php
Classes/
  Autoloader.php
  ClassA.php - class ClassA {}
  ClassB.php - class ClassB {}
  Business/
    ClassC.php - namespace Business; classC {}
    Deeper/
      ClassD.php - namespace Business\Deeper; classD {}

0
<?php
spl_autoload_register(function ($classname){
   // for security purpose
   //your class name should match the name of your class "file.php"
   $classname = str_replace("..", "", $classname);
   require_once __DIR__.DIRECTORY_SEPARATOR.("classes/$classname.class.php");
});
try {
  $new = new Class1();
} catch (Exception $e) {
   echo "error = ". $e->getMessage();
}
?>

1
このコードは質問に答えることがありますが、このコードが質問に答える理由や方法に関する追加のコンテキストを提供すると、長期的な価値が向上します。
イーサン、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.