自動ロードで PHP 名前空間を使用するにはどうすればよいですか?
質問
自動ロードと名前空間を使用しようとすると、次のエラーが発生します。
致命的な誤り: クラス「Class1」が見つかりません /usr/local/www/apache22/data/public/php5.3/test.php の上 10行目
誰か私が間違っていることを教えてくれませんか?
これが私のコードです:
クラス1.php:
<?php
namespace Person\Barnes\David
{
class Class1
{
public function __construct()
{
echo __CLASS__;
}
}
}
?>
テスト.php:
<?php
function __autoload($class)
{
require $class . '.php';
}
use Person\Barnes\David;
$class = new Class1();
?>
解決
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):
明確にするために、私の「使用...」の使用法as" は例を簡略化するためのものです。
代替案は次のとおりでした。
$class = new Person\Barnes\David\Class1();
または
use Person\Barnes\David\Class1;
// ...
$class = new Class1();
他のヒント
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 を使用している場合は、古い構文に置き換えてください。関数 __autoload($class)
あなたの __autoload
関数は、名前空間名を含む完全なクラス名を受け取ります。
これは、あなたの場合、 __autoload
関数は ' を受け取りますPerson\Barnes\David\Class1
'だけでなく'Class1
'.
したがって、そのような「より複雑な」名前に対処するには、自動読み込みコードを変更する必要があります。よく使用される解決策は、名前空間の「レベル」ごとに 1 レベルのディレクトリを使用してファイルを整理し、自動ロード時に ' を置き換えることです。\
' による名前空間名 DIRECTORY_SEPARATOR
.
私は次のようなことをします: この 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___
}
この宝石を見つけたのは、 フライシステム
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);
}
});
次の 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();
お役に立てれば。
同じ問題があり、ちょうどこれを見つけました:
含まれるクラスの名前空間に一致するサブフォルダー構造を作成すると、オートローダーを定義する必要さえなくなります。
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 による実用的なソリューションについては、ここを参照してください。
を使用するのには注意点があります。これは断然最速の方法ですが、すべてのファイル名が小文字であることが前提となります。
spl_autoload_extensions(".php");
spl_autoload_register();
例えば:
SomeSuperClass クラスを含むファイルには somesuperclass.php という名前を付ける必要があります。ファイルの名前が SomeSuperClass.php の場合、これは Linux などの大文字と小文字を区別するファイルシステムを使用する場合に注意が必要ですが、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;
});
最近、tanerkuc の回答が非常に役立つことがわかりました。それを使用して追加したかっただけです strrpos()
+ substr()
よりもわずかに速いです explode()
+ end()
:
spl_autoload_register( function( $class ) {
$pos = strrpos( $class, '\\' );
include ( $pos === false ? $class : substr( $class, $pos + 1 ) ).'.php';
});
比較的初心者や、理論を一切使わずに単純な spl_autoload_register() のセットアップを希望する人のために、2 セントを投入します。クラスごとに 1 つの PHP ファイルを作成し、その PHP ファイルにクラス名と同じ名前を付け、クラス ファイルを問題の PHP ファイルと同じディレクトリに保存するだけで、これは機能します。
spl_autoload_register(function ($class_name) {
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . $class_name . '.php';
});
この関数内の部分をグーグルで調べると、それがどのように機能するかがわかるはずです。追伸:私は Linux を使用していますが、これは Linux でも動作します。Windowsの人はまずそれをテストしてください。
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 BusinessDeeper classD {}
この簡単なハックを 1 行で使用します。
spl_autoload_register(function($name){
require_once 'lib/'.str_replace('\\','/',$name).'.php';
});
<?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();
}
?>