如何使用自动加载的PHP名称空间?
我尝试使用自动加载和命名空间时遇到此错误:
致命错误:第10行中的/usr/local/www/apache22/data/public/php5.3/test.php中找不到类“Class1”
谁能告诉我我做错了什么?
这是我的代码:
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(); ?>
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”是为了简化这个例子。
替代scheme如下:
$class = new Person\Barnes\David\Class1();
要么
use Person\Barnes\David\Class1; // ... $class = new Class1();
正如Pascal MARTIN所提到的,你应该用DIRECTORY_SEPARATORreplace'\',例如:
$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'; include($filename);
此外,我会build议你重新组织的结构,使代码更具可读性。 这可能是一个替代scheme:
目录结构:
ProjectRoot |- lib
File: /ProjectRoot/lib/Person/Barnes/David/Class1.php
<?php namespace Person\Barnes\David class Class1 { public function __construct() { echo __CLASS__; } } ?>
- 为您定义的每个名称空间创build子目录。
文件: /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 recomendation自动加载器声明。 如果您仍然使用PHP 4,请将其replace为旧的语法:function __autoload($ class)
您的__autoload
函数将收到完整的类名称,包括名称空间名称。
这意味着,在你的情况下, __autoload
函数将会收到' Person\Barnes\David\Class1
',而不是' Class1
'。
所以,你必须修改你自动加载的代码,来处理那种“更复杂”的名字; 一个经常使用的解决scheme是使用名称空间的“级别”级别的目录来组织文件,而在自动加载时,用DIRECTORY_SEPARATOR
replace名称空间名称中的“ \
”。
我做这样的事情:
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___ }
我从Flysystemfind了这颗gem
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); } });
我发现自动加载函数只接收“完整的”类名 – 所有的名字空间都在它之前 – 在以下两种情况下:
[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],以下两种情况也适用:
[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();
希望这可以帮助。
有同样的问题,只是发现这一点:
当您创build与包含类的名称空间匹配的子文件夹结构时,您甚至不需要定义自动加载器。
spl_autoload_extensions(".php"); // comma-separated list spl_autoload_register();
它像一个魅力工作
更多信息: http : //www.php.net/manual/en/function.spl-autoload-register.php#92514
编辑:这会导致Linux上的问题,因为反斜杠…看到这里的工作解决schemeimmeëmosol
命名空间自动加载在Windows下工作,但不在Linux上
使用有一个问题,虽然它是迄今为止最快的方法,它也期望所有的文件名都是小写的。
spl_autoload_extensions(".php"); spl_autoload_register();
例如:
包含SomeSuperClass类的文件需要命名为someSuperclass.php,如果您的文件被命名为SomeSuperClass.php而不是Windows下的问题,则在使用像Linux这样的区分大小写的文件系统时,这是一个难题。
在你的代码中使用__autoload可能仍然适用于当前版本的PHP,但是期望这个特性将被弃用,并在将来被删除。
那么剩下什么select:
该版本将与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; });
我将为相对初学者投入我的两分钱,或者不想要一个简单的spl_autoload_register()设置,而不需要所有的理论:只需为每个类创build一个php文件,命名该php文件与您的类名相同,并保存类文件在你的PHP文件在相同的目录中,然后这将工作:
spl_autoload_register(function ($class_name) { require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . $class_name . '.php'; });
使用Googlesearch这个函数应该能够解决它的工作原理。 PS:我使用Linux,这在Linux上运行。 Windows的人应该先testing一下。
我最近发现tanerkuc的回答非常有帮助! 只是想补充说,使用strrpos()
+ substr()
比explode()
+ end()
稍快:
spl_autoload_register( function( $class ) { $pos = strrpos( $class, '\\' ); include ( $pos === false ? $class : substr( $class, $pos + 1 ) ).'.php'; });
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 {}