如何在自动加载中使用 PHP 命名空间?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1830917/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I use PHP namespaces with autoload?
提问by David Barnes
I get this error when I try to use autoload and namespaces:
当我尝试使用自动加载和命名空间时出现此错误:
Fatal error:Class 'Class1' not found in /usr/local/www/apache22/data/public/php5.3/test.phpon line 10
致命错误:在第 10 行的/usr/local/www/apache22/data/public/php5.3/test.php 中找不到“Class1”类
Can anyone tell me what I am doing wrong?
谁能告诉我我做错了什么?
Here is my code:
这是我的代码:
Class1.php:
类1.php:
<?php
namespace Person\Barnes\David
{
class Class1
{
public function __construct()
{
echo __CLASS__;
}
}
}
?>
test.php:
测试.php:
<?php
function __autoload($class)
{
require $class . '.php';
}
use Person\Barnes\David;
$class = new Class1();
?>
回答by tanerkay
Class1 is not in the global scope.
Class1 不在全局范围内。
See below for a working example:
请参阅下面的工作示例:
<?php
function __autoload($class)
{
$parts = explode('\', $class);
require end($parts) . '.php';
}
use Person\Barnes\David as MyPerson;
$class = new MyPerson\Class1();
Edit (2009-12-14):
编辑(2009-12-14):
Just to clarify, my usage of "use ... as" was to simplify the example.
只是为了澄清,我使用“use ... as”是为了简化示例。
The alternative was the following:
替代方案如下:
$class = new Person\Barnes\David\Class1();
or
或者
use Person\Barnes\David\Class1;
// ...
$class = new Class1();
回答by Kostanos
As mentioned Pascal MARTIN, you should replace the '\' with DIRECTORY_SEPARATOR for example:
如前所述,Pascal MARTIN,您应该用 DIRECTORY_SEPARATOR 替换“\”,例如:
$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('\', DIRECTORY_SEPARATOR, $class) . '.php';
include($filename);
Also I would suggest you to reorganize the dirrectory structure, to make the code more readable. This could be an alternative:
此外,我建议您重新组织目录结构,以使代码更具可读性。这可能是另一种选择:
Directory structure:
目录结构:
ProjectRoot
|- lib
File: /ProjectRoot/lib/Person/Barnes/David/Class1.php
文件: /ProjectRoot/lib/Person/Barnes/David/Class1.php
<?php
namespace Person\Barnes\David
class Class1
{
public function __construct()
{
echo __CLASS__;
}
}
?>
- Make the sub directory for each namespace you are defined.
- 为您定义的每个命名空间创建子目录。
File: /ProjectRoot/test.php
文件: /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();
- I used php 5 recomendation for autoloader declaration. If you are still with PHP 4, replace it with the old syntax: function __autoload($class)
- 我使用 php 5 推荐进行自动加载器声明。如果您仍然使用 PHP 4,请将其替换为旧语法:function __autoload($class)
回答by Pascal MARTIN
Your __autoloadfunction will receive the full class-name, including the namespace name.
您的__autoload函数将收到完整的类名,包括命名空间名称。
This means, in your case, the __autoloadfunction will receive 'Person\Barnes\David\Class1', and not only 'Class1'.
这意味着,在您的情况下,该__autoload函数将收到“ Person\Barnes\David\Class1”,而不仅仅是“ Class1”。
So, you have to modify your autoloading code, to deal with that kind of "more-complicated" name ; a solution often used is to organize your files using one level of directory per "level" of namespaces, and, when autoloading, replace '\' in the namespace name by DIRECTORY_SEPARATOR.
因此,您必须修改自动加载代码,以处理那种“更复杂”的名称;经常使用的一种解决方案是使用命名空间“级别”的一级目录来组织文件,并且在自动加载时,\将命名空间名称中的' '替换为DIRECTORY_SEPARATOR.
回答by tika
I do something like this: See this GitHub Example
我做这样的事情:看这个 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___
}
回答by boksiora
I found this gem from Flysystem
我从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);
}
});
回答by Daniel Rhodes
I see that the autoload functions only receive the "full" classname - with all the namespaces preceeding it - in the following two cases:
我看到在以下两种情况下,自动加载函数只接收“完整”类名 - 前面有所有命名空间:
[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();
I see that the autoload functions DO NOT receive the full classname in the following case:
我看到在以下情况下自动加载函数不会收到完整的类名:
[c] use The\Full\Namespace; (at the top of your source file) followed by $a = new CoolClass();
UPDATE: [c] is a mistake and isn't how namespaces work anyway. I can report that, instead of [c], the following two cases also work well:
更新: [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();
Hope this helps.
希望这可以帮助。
回答by princebillyGK
I use this simple hack in one line:
我在一行中使用了这个简单的 hack:
spl_autoload_register(function($name){
require_once 'lib/'.str_replace('\','/',$name).'.php';
});
回答by Alan
I recently found tanerkuc's answer very helpful! Just wanted to add that using strrpos()+ substr()is slightly faster than explode()+ end():
我最近发现 tanerkuc 的回答非常有帮助!只是想补充一点,使用strrpos()+substr()比explode()+稍快end():
spl_autoload_register( function( $class ) {
$pos = strrpos( $class, '\' );
include ( $pos === false ? $class : substr( $class, $pos + 1 ) ).'.php';
});
回答by Alan
I'll throw in my two cents for relative beginners or whatnot wanting a simple spl_autoload_register() setup without all the theory: Just create one php file for each class, name that php file the same as your class name, and keep your class files in the same directory as your php file in question, then this will work:
我会为相对的初学者或不想要简单的 spl_autoload_register() 设置而没有所有理论的东西投入我的两分钱:只需为每个类创建一个 php 文件,将该 php 文件命名为与您的类名相同的名称,并保留您的类文件在与您的 php 文件相同的目录中,然后这将起作用:
spl_autoload_register(function ($class_name) {
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . $class_name . '.php';
});
Googling the pieces inside this function should answer how it works. PS: I use Linux, and this works on Linux. Windows folks should test it out first.
谷歌搜索这个函数内的部分应该可以回答它是如何工作的。PS:我使用 Linux,这适用于 Linux。Windows 人应该先测试一下。
回答by Yuvraj Singh Shekhawat
https://thomashunter.name/blog/simple-php-namespace-friendly-autoloader-class/
https://thomashunter.name/blog/simple-php-namespace-friendly-autoloader-class/
You'll want to put your class files into a folder named Classes, which is in the same directory as the entry point into your PHP application. If classes use namespaces, the namespaces will be converted into the directory structure. Unlike a lot of other auto-loaders, underscores will not be converted into directory structures (it's tricky to do PHP < 5.3 pseudo namespaces along with PHP >= 5.3 real namespaces).
您需要将类文件放入名为 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');
You'll want to place the following code into your main PHP script (entry point):
您需要将以下代码放入您的主要 PHP 脚本(入口点)中:
require_once("Classes/Autoloader.php");
Here's an example directory layout:
这是一个示例目录布局:
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 {}

