Автозагрузка с пространством имен — Неустранимая ошибка: неперехваченная ошибка: класс «MyClass» не найден

Использование spl_autoload_register() с классом, использующим пространство имен, вызывает это сообщение об ошибке: Неустранимая ошибка: неперехваченная ошибка: класс "MyClass" не найден...

Перед этим сообщением об ошибке автозагрузчик выдает эхо "...MyClass.php IS found".

Используются два файла: "/index.php" (в корневом каталоге) и "/classes/MyClass.php".

Индекс.php:

declare(strict_types=1);

define ('ROOT_DIR', __DIR__ . '/');
define ('CLASS_DIR', ROOT_DIR . 'classes/');

spl_autoload_register(function($class) {
    $filepath = CLASS_DIR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
    if (file_exists($filepath)) {
        require_once $filepath;
        echo('<br /><b>' . $filepath . '</b> IS found.<br />');
    } else {
        echo('<br /><b>' . $filepath . '</b> not found.<br />');
        exit;
    }
});

$myclass = new MyClass();

МойКласс.php:

declare(strict_types=1);

namespace App\Classes

class MyClass
{
    // ...
}

Кто-нибудь знает, как это решить?

Согласно https://www.php-fig.org/psr/psr-4/, требуется имя поставщика, поэтому я использую «Приложение» в качестве имени пространства имен верхнего уровня, хотя это не так. каталог (потому что мой сайт использует корень сервера).

Я также пытался добавить «use App/classes/Myclass» в index.php перед «$myclass = new MyClass()», но это вызывает еще больше проблем, потому что автозагрузчик будет искать каталог «/classes/App/Classes». ..

С удалением пространства имен из класса все работает нормально, и я могу использовать функции класса через $myclass. Но я хотел бы начать использовать пространства имен... Любая помощь будет очень признательна! <3

Вывод: Либо строка "$myclass = new App\Classes\MyClass();" или "use App\Classes\MyClass;" следует использовать.

Таким образом, невозможно использовать корень сервера, имея при этом имя пространства имен верхнего уровня ("App") с этой функцией автозагрузки. функция должна быть расширена, чтобы учесть эту возможность. А каталог «classes» будет переименован в «Classes». Я опубликую свое решение, когда оно будет готово!

Для получения более подробной информации прочитайте комментарии под ответом @IMSoP (Спасибо вам большое спасибо за помощь!)

Решение:

declare(strict_types=1);

namespace App;

define ('ROOT_DIR', $_SERVER['DOCUMENT_ROOT'] . '/');
define ('BASE_DIR', __DIR__ . '/');
define ('TOP_LEVEL_NAMESPACE_NAME', __NAMESPACE__ . '/');

spl_autoload_register(function($class) {
    if (BASE_DIR == ROOT_DIR . TOP_LEVEL_NAMESPACE_NAME) {
        $filepath = ROOT_DIR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
    } else {
        $filepath = BASE_DIR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
        $filepath = str_replace(TOP_LEVEL_NAMESPACE_NAME, '', $filepath);
    }
    if (file_exists($filepath)) {
        require_once $filepath;
    } else {
        echo('Class <b>' . end(explode('\\', $class)) . '.php</b> was not found.');
        exit;
    }
});

use App\Classes\MyClass;

$myclass = new MyClass();

Это решение работает независимо от того, находится ли приложение в каталоге с тем же именем, что и имя пространства имен верхнего уровня, или где-либо еще!

С namespace App\Classes\MyClass ваше полное имя класса на самом деле будет App\Classes\MyClass\MyClass, что является нонсенсом.

deceze 06.02.2023 11:18

@deceze Спасибо! Я думал, что сделал это в первый раз правильно, но потом кто-то упомянул, что я не всегда использовал полные имена классов, и я подумал, что это должно быть место, где я должен что-то изменить (потому что это была единственная часть в моем коде, где я использую пространство имен)... Но я неправильно понял, и я должен использовать полное имя класса в строке с "$myclass = new MyClass()" (или вместо этого использовать "use")... Этим решениям нужен автозагрузчик функция должна быть скорректирована, что я и сделаю.. В любом случае, большое спасибо за ваш комментарий! Я изменил пространство имен обратно (без имени класса)

1337noobie 06.02.2023 11:41
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
2
97
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Возможно, вы захотите прочитать страницы руководств по автозагрузке и пространствам имен, чтобы убедиться, что вы понимаете ключевые понятия.

Вы объявили класс с именем MyClass внутри пространства имен App\Classes; это означает, что его полное имя App\Classes\MyClass - это имя, которое вам нужно вызывать из-за пределов этого пространства имен. Одновременно мог существовать другой класс, полное имя которого было просто MyClass, потому что его не было ни в одном пространстве имен, и любое количество других в других пространствах имен, таких как App\Security\MyClass, App\UI\MyClass и т. д.

Затем вы попытались сослаться на класс в index.php с именем MyClass, который запускает автозагрузчик. Автозагрузчик преобразует его в путь типа .../classes/MyClass.php и загружает нужный файл; но этот файл определяет ваш класс с пространством имен. Таким образом, после завершения работы автозагрузчика класса с именем MyClass нет, только App\Classes\MyClass, и код завершается ошибкой.

Если вместо этого вы напишете new App\Classes\MyClass, вы получите противоположную проблему: в ваш автозагрузчик передается строка 'App\Classes\MyClass', и вы переводите ее в путь к файлу, например '.../classes/App/Classes/MyClass.php', но это не то место, где находится ваш файл. (Добавление use App\ClassesMyClass делает то же самое — операторы use просто помогают компилятору избегать слишком частой записи полного имени.)

Что вам нужно сделать, так это:

  • Постоянно используйте полные имена классов (или псевдонимы с use)
  • Расположите свои файлы в соответствии со структурой вашего пространства имен, чтобы ваш автозагрузчик мог их найти, что обычно означает каталог для каждого пространства имен.

Большое спасибо за Ваш ответ! У меня два вопроса: ...1) Я не использую полные имена классов? (я думал, что делаю это, как описано в psr-4, но я не смог использовать команду «использовать» в index.php, вероятно, по той причине, которую вы упомянули) ... 2) Нельзя ли использовать корень сервера, сохраняя при этом имя пространства имен верхнего уровня? ("Приложение" в данном случае)

1337noobie 06.02.2023 10:44

@ 1337noobie 1) В этой строке кода в вашем вопросе не используется полное имя: $myclass = new MyClass(); Оно должно быть либо $myclass = new App\Classes\MyClass();, либо иметь use App\Classes\MyClass; вверху файла. 2) Вы можете расположить свои файлы так, как хотите, вы просто пишете любую логику, необходимую в вашей функции автозагрузчика, чтобы перевести имя в местоположение; но весь смысл пространств имен в том, что у вас может быть два класса с именами MyClass, поэтому размещение всех ваших классов в одном плоском каталоге не сработает.

IMSoP 06.02.2023 10:55

Я исправил пространство имен, изменил его с «App\Classes» на «App\Classes\MyClass», но та же проблема все еще возникает... Второе предложение, которое вы сделали, заключалось в том, чтобы соответствовать структуре пространства имен, но если я это сделаю, то мне пришлось бы переместить мои файлы в каталог под названием «Приложение», это правильно? Означает ли это, что тогда нельзя будет использовать корневой каталог сервера?

1337noobie 06.02.2023 10:56

@ 1337noobie Я только что ответил на эту часть: разместите их в любых каталогах, которые вам нравятся, но если у вас есть два класса с именами App\UI\Control и App\Permission\Control, они не могут быть файлами с именем «Control.php» в одном и том же каталоге. Вы можете назвать их «App__UI__Control.php» и «App__Permission__Control.php», если хотите, но более распространенным является просто использование каталога для каждого пространства имен.

IMSoP 06.02.2023 10:58

@ 1337noobie 1) Поймите, что если вы называете свой класс App\Classes\MyClass, что вы сделали, используя пространство имен, то вам также нужно называть его этим именем с помощью new App\Classes\MyClass. 2) Когда вы делаете new App\Classes\MyClass и ваш автозагрузчик получает строку "App\Classes\MyClass", то вам нужно написать свой автозагрузчик таким образом и выложить ваши файлы таким образом, чтобы правильный файл мог быть загружен из имени "App\Classes\MyClass".

deceze 06.02.2023 10:59

Кроме того, вы говорите «мое второе предложение», но я прямо сказал в ответе, что вам нужно исправить обе вещи.

IMSoP 06.02.2023 10:59

@IMPSoP Еще раз спасибо за ваш ответ! Таким образом, единственным решением было бы изменить мою функцию автозагрузчика, чтобы вручную удалить любую часть «Приложения» и заменить «Классы» (верхний регистр в пространстве имен) на «классы» (нижний регистр, имя каталога), чтобы он будет правильно соответствовать моей структуре каталогов? ... Я снова прочитаю ваши комментарии, я чувствую себя глупо, если неправильно понял то, что вы написали раньше ...

1337noobie 06.02.2023 11:00

@ 1337noobie «Классы» - довольно бессмысленное имя пространства имен. Если вы собираетесь поместить все в это пространство имен, зачем вообще беспокоиться о пространствах имен?

IMSoP 06.02.2023 11:01

Я действительно очень ценю ваши отзывы! Вы не сказали это явно, но я предполагаю, что мне придется изменить функцию автозагрузчика так, как я упомянул выше (путем удаления «приложения» вручную из пути и т. д.), чтобы я мог использовать «новое приложение \ классы \ MyClass ()" без каких-либо проблем. @IMSoP Я все еще учусь, поэтому надеюсь, что не слишком раздражал вас своей медлительностью в понимании... Еще раз спасибо за вашу помощь!

1337noobie 06.02.2023 11:14

@ 1337noobie Смысл пространств имен в том, чтобы структурировать ваш код таким образом, чтобы он имел для вас смысл. Обычно каталоги располагаются одинаково, потому что люди обычно считают полезным иметь связанные классы в одном каталоге.

IMSoP 06.02.2023 11:14

@IMSoP Я согласен, это кажется действительно полезным ... До сих пор я хотел только проверить, могу ли я заставить работать автозагрузчик, поэтому у меня нет подкаталогов в моем каталоге классов (и пространстве имен) для более конкретных целей ... Честно говоря, я даже не думал, что далеко вперед, я просто хотел сначала исправить ошибки... Я просто чувствую разочарование, что я не могу использовать и корень моего сервера, и имя пространства имен верхнего уровня одновременно, с общая функция автозагрузчика, которую я использовал...

1337noobie 06.02.2023 11:26

@ 1337noobie Я думаю, что это, возможно, случай попытки двигаться слишком медленно: пытаясь использовать пространства имен «немного», вы на самом деле пытались сделать что-то более сложное, потому что это не соответствует ни одному из примеров, которые вы смотрим. Если вместо App\Classes вы сделаете свое первое пространство имен App\NotYetCategorised, будет намного понятнее, как оно соотносится с примерами, которые вы найдете в чужом коде.

IMSoP 06.02.2023 11:31

Это заняло некоторое время, но мне удалось решить эту проблему! :) Я добавил свое решение в пост... Спасибо за ваше время и ваш совет! @IMSoP

1337noobie 06.02.2023 16:08

Другие вопросы по теме