Как использовать пространства имен PHP с автозагрузкой? - PullRequest
92 голосов
/ 02 декабря 2009

Я получаю эту ошибку при попытке использовать автозагрузку и пространства имен:

Фатальная ошибка: Класс '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();

?>

Ответы [ 13 ]

112 голосов
/ 09 декабря 2009

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):

Просто чтобы уточнить, мое использование слова "использовать ... как" должно было упростить пример.

Альтернатива была следующая:

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

или

use Person\Barnes\David\Class1;

// ...

$class = new Class1();
25 голосов
/ 14 мая 2013

Как уже упоминалось, Паскаль 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)
17 голосов
/ 02 декабря 2009

Ваша __autoload функция получит полное имя класса, включая имя пространства имен.

Это означает, что в вашем случае функция __autoload получит Person\Barnes\David\Class1, а не только Class1.

Итак, вы должны изменить свой автозагрузочный код, чтобы иметь дело с такого рода «более сложным» именем; часто используемое решение состоит в том, чтобы организовать ваши файлы, используя один уровень каталога на «уровень» пространств имен, и при автозагрузке заменить «\» в имени пространства имен на DIRECTORY_SEPARATOR.

11 голосов
/ 31 мая 2015

Я делаю что-то вроде этого: Смотрите этот пример 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 голосов
/ 15 февраля 2015

Я нашел этот драгоценный камень из 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 голосов
/ 21 августа 2013

Я вижу, что функции автозагрузки получают только "полное" имя класса - со всеми предшествующими ему пространствами имен - в следующих двух случаях:

[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();

Надеюсь, это поможет.

1 голос
/ 29 августа 2018

Я использую этот простой взлом в одну строку:

spl_autoload_register(function($name){
        require_once 'lib/'.str_replace('\\','/',$name).'.php';
    });
1 голос
/ 26 октября 2017

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 голос
/ 22 августа 2016

Я добавлю свои два цента для начинающих или чего-то еще, желающих простую установку 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 должны сначала проверить это.

1 голос
/ 05 августа 2016

Недавно я нашел ответ tanerkuc очень полезным! Просто хотел добавить, что использование strrpos() + substr() немного быстрее, чем explode() + end():

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