Как использовать пространства имен PHP с автозагрузкой?
Я получаю эту ошибку, когда пытаюсь использовать autoload и namespaces:
Неустранимая ошибка: Класс 'Class1' не найден в /usr/local/www/apache22/data/public/php5.3/test.php на строка 10
Может ли кто-нибудь сказать мне, что я делаю неправильно?
Вот мой код:
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();
?>
Ответы
Ответ 1
Класс 1 не входит в глобальную область.
Ниже приведен рабочий пример:
<?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();
Ответ 2
Как упоминалось Паскаль МАРТИН, вы должны заменить '\' на DIRECTORY_SEPARATOR, например:
$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
include($filename);
Кроме того, я бы предложил вам перестроить структуру dirrectory, чтобы сделать код более удобочитаемым. Это может быть альтернативой:
Структура каталогов:
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)
Ответ 3
Ваша функция __autoload
получит полное имя класса, включая имя пространства имен.
Это означает, что в вашем случае функция __autoload
получит "Person\Barnes\David\Class1
", а не только "Class1
".
Итак, вам нужно изменить свой автозагрузочный код, чтобы иметь дело с таким "более сложным" именем; часто используемым решением является организация ваших файлов с использованием одного уровня каталога на "уровень" пространств имен и при автозагрузке заменить "\
" на имя пространства имен на DIRECTORY_SEPARATOR
.
Ответ 4
Я делаю что-то вроде этого:
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___
}
Ответ 5
Я вижу, что функции автозагрузки получают только "полное" имя класса - со всеми пробелами, предшествующими им, - в следующих двух случаях:
[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();
Надеюсь, что это поможет.
Ответ 6
Я нашел этот камень из 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);
}
});
Ответ 7
имел ту же проблему и только что нашел это:
Когда вы создаете структуру подпапки, соответствующую пространствам имен содержащихся классов, вам даже не придется определять автозагрузчик.
spl_autoload_extensions(".php"); // comma-separated list
spl_autoload_register();
Он работал как шарм
Дополнительная информация здесь: http://www.php.net/manual/en/function.spl-autoload-register.php#92514
EDIT: это вызывает проблему в Linux из-за обратной косой черты... См. здесь для рабочего решения immeëmosol
Пространство имен Autoload работает под окнами, но не в Linux
Ответ 8
Использование имеет gotcha, хотя это, безусловно, самый быстрый метод, он также ожидает, что все ваши имена файлов будут более строчными.
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;
});
Ответ 9
Я брошу свои два цента для относительных новичков или не хочу простой установки spl_autoload_register() без всякой теории:
Просто создайте один php файл для каждого класса, назовите этот php файл так же, как имя вашего класса, и сохраните файлы классов в том же каталоге, что и ваш php файл, тогда это будет работать:
spl_autoload_register(function ($class_name) {
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . $class_name . '.php';
});
Включение функции в эту функцию должно отвечать тому, как она работает.
PS: Я использую Linux, и это работает на Linux. Сначала люди Windows должны проверить это.
Ответ 10
https://thomashunter.name/blog/simple-php-namespace-friendly-autoloader-class/
Вы хотите поместить свои файлы классов в папку с именем Classes, которая находится в том же каталоге, что и точка входа в ваше приложение PHP. Если классы используют пространства имен, пространства имен будут преобразованы в структуру каталогов. В отличие от многих других автозагрузчиков, символы подчеркивания не будут преобразованы в структуры каталогов (его сложно использовать псевдопространства PHP и lt вместо 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 script (точка входа):
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 {}
Ответ 11
Недавно я нашел ответ tanerkuc очень полезным! Просто хотел добавить, что использование strrpos()
+ substr()
немного быстрее, чем explode()
+ end()
:
spl_autoload_register( function( $class ) {
$pos = strrpos( $class, '\\' );
include ( $pos === false ? $class : substr( $class, $pos + 1 ) ).'.php';
});