За последние 24 часа нас посетили 19347 программистов и 1636 роботов. Сейчас ищут 1905 программистов ...

Autoload with Namespace

Тема в разделе "PHP для новичков", создана пользователем Danil005, 5 авг 2017.

  1. Danil005

    Danil005 Активный пользователь

    С нами с:
    2 янв 2015
    Сообщения:
    528
    Симпатии:
    30
    Не получается сделать Autoload с Namespace, я допустил ошибку, но в упор не вижу:

    PHP:
    1. class NamespaceAutoloader {
    2.  
    3.     protected $namespacesMap = [];
    4.     public function addNamespace($namespace, $rootDir) {
    5.         if (is_dir($rootDir)) {
    6.             $this->namespacesMap[$namespace] = $rootDir;
    7.             return true;
    8.         }
    9.      
    10.         return false;
    11.     }
    12.  
    13.     public function register() {
    14.         spl_autoload_register(array($this, 'autoload'));
    15.     }
    16.  
    17.     protected function autoload($class) {
    18.         $pathParts = explode('\\', $class);
    19.      
    20.         if (is_array($pathParts)) {
    21.             $namespace = array_shift($pathParts);
    22.          
    23.             if (!empty($this->namespacesMap[$namespace])) {
    24.                 $filePath = $this->namespacesMap[$namespace] . '/' . implode('/', $pathParts) . '.php';
    25.                 require_once $filePath;
    26.                 return true;
    27.             }
    28.         }
    29.      
    30.         return false;
    31.     }
    32. }
    Потом Core:

    PHP:
    1. namespace Core;
    2. use \NamespaceAutoloader;
    3.  
    4.  
    5. require_once( __DIR__ . '/Autoloader/AutoloaderNameSpace.php' );
    6. $load=new NamespaceAutoloader();
    7.  
    8. require_once( __DIR__ . '/classes.php' );
    classes.php:

    PHP:
    1. $load->addNamespace('test', __DIR__ . '/base/test');
    2.  
    3. $load->register();
    test.php

    PHP:
    1. <?
    2.  
    3. namespace test;
    4.  
    5. class Admin {
    6.     public function test() {
    7.         echo "1";
    8.     }
    9. }
    index.php

    PHP:
    1. <?include($_SERVER['DOCUMENT_ROOT'].'/system/core/core.php');
    2.  
    3. Admin::test();
    И ошибка:
    Fatal error: Uncaught Error: Class 'Admin' not found in E:\Server\OpenServer\domains\local.vixed.ru\index.php:3 Stack trace: #0 {main} thrown in E:\Server\OpenServer\domains\local.vixed.ru\index.php on line 3
     
  2. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
    Посмотри готовый PSR для авто загрузки или через composer.
    Как Admin должен найтись если он в test namespace?
    --- Добавлено ---
    Не надо использовать одинарные <? вместо них <?php, ну исключение для короткой записи echo: <?=$string?>
     
  3. Danil005

    Danil005 Активный пользователь

    С нами с:
    2 янв 2015
    Сообщения:
    528
    Симпатии:
    30
    Почему?
     
  4. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.589
    Симпатии:
    1.763
    Это устарело ещё когда я начинал 4 года назад
     
  5. Danil005

    Danil005 Активный пользователь

    С нами с:
    2 янв 2015
    Сообщения:
    528
    Симпатии:
    30
    И в чем разница? <? и <?php ?
     
  6. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.589
    Симпатии:
    1.763
    В том, что <? используется, к примеру, ещё в XML
     
  7. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.799
    Симпатии:
    1.331
    Адрес:
    Лень
    PHP:
    1. <?php
    2.  
    3. # P.s: Заготовка для головастых - не стоит упоминать об отдельных файлов для каждого пространства
    4.  
    5. namespace Aero
    6. {
    7.     class AeroBase
    8.     {
    9.         protected static $NAMESPACESMAP = [
    10.             App\Application::class => 'Application\C.Application'
    11.         ];
    12.      
    13.         public static function setPatchMap( string $NAME, string $PATCH )
    14.         {
    15.             self::$NAMESPACESMAP[$NAME] = $PATCH;
    16.         }
    17.         public static function autoload( $CLASS )
    18.         {
    19.             if (1)
    20.             {
    21.                 echo "{$CLASS}<br>" . PHP_EOL;
    22.             }
    23.          
    24.             if ( isset ( self::$NAMESPACESMAP[$CLASS] ) )
    25.             {
    26.                 $CLASS = self::$NAMESPACESMAP[$CLASS];
    27.             }
    28.          
    29.             include dirname ( __FILE__ ) . DIRECTORY_SEPARATOR . strtr ( $CLASS, '\\', DIRECTORY_SEPARATOR ) . '.php';
    30.         }
    31.     }
    32. }
    33.  
    34. namespace
    35. {
    36.  
    37.     spl_autoload_register ( [ \Aero\AeroBase::class, 'autoload' ] );
    38. }
     
  8. Danil005

    Danil005 Активный пользователь

    С нами с:
    2 янв 2015
    Сообщения:
    528
    Симпатии:
    30
    @MouseZver, а теперь можешь объяснить что да как?
    --- Добавлено ---
    В ключе ты использовал NameSpace и название класса, а где значение - путь?
     
  9. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.799
    Симпатии:
    1.331
    Адрес:
    Лень
    разве ты не ответил на свой вопрос ?
     
  10. Danil005

    Danil005 Активный пользователь

    С нами с:
    2 янв 2015
    Сообщения:
    528
    Симпатии:
    30
    Проблема в том, что не работает.
    PHP:
    1. protected static $NAMESPACESMAP = [
    2.          Example\ex1::exs => __DIR__ . 'classes_example/ex1.php'
    3. ];
    PHP:
    1. <?//Example #1;
    2.  
    3. namespace Example\ex1;
    4. class exs {
    5.     public static function test() {
    6.         echo '1';
    7.     }
    8. }
    PHP:
    1. <?include('namespace.php');
    2.  
    3. Exs::test();
    Код (Text):
    1. Exs
    2. Aero\Example\ex1
    3.  
    4. Warning: include(E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\Aero\Example\ex1.php): failed to open stream: No such file or directory in E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\namespace.php on line 28
    5.  
    6. Warning: include(): Failed opening 'E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\Aero\Example\ex1.php' for inclusion (include_path='.;e:/server/openserver/modules/php/PHP-7;e:/server/openserver/modules/php/PHP-7/PEAR/pear') in E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\namespace.php on line 28
    7.  
    8. Fatal error: Class 'Aero\Example\ex1' not found in E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\namespace.php on line 23
    Если сделать так:
    \Example\ex1::exs => __DIR__ . 'classes_example/ex1.php'
    Та же проблема будет.
     
  11. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.799
    Симпатии:
    1.331
    Адрес:
    Лень
    тестируй как работает наймспейс. Далеко до них как и с тривиальным понятием директорий. Если ложить большой болт на прочтение ошибок, то с таким же успехом можно положить на программирование и идти гамать дальше в игрушки.
    --- Добавлено ---
    я не даром прописал пару строк чтобы следить кто что юзнулся
    PHP:
    1. if (1)
    2.             {
    3.                 echo "{$CLASS}<br>" . PHP_EOL;
    4.             }
    --- Добавлено ---
    namespace Aero;
    PHP:
    1.         protected static $NAMESPACESMAP = [
    2.             App\Application::class => 'Application\C.Application'
    3.         ];
    App\Application::class - Да, пространство с классом Application
    Приставка ::class говорит о том что нужно погуглить и прочесть для любопытства "чейт за хрень ?". Данная хрень наследует нынешнее пространство Аеро, тобишь получается автодобавление 'Aero\App\Application'

    'Application\C.Application' - Сам путь к классу. Недаром:
    PHP:
    1.             if ( isset ( self::$NAMESPACESMAP[$CLASS] ) )
    2.             {
    3.                 $CLASS = self::$NAMESPACESMAP[$CLASS];
    4.             }
    И в итоге подключается файл с классом
    PHP:
    1. <?php
    2.  
    3. namespace Aero\App;
    4.  
    5. class Application
    6. {
    7.    
    8. }
     
  12. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Может мне кто объяснить зачем здесь используется класс автозагрузки?
     
  13. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.799
    Симпатии:
    1.331
    Адрес:
    Лень
    для дальнейшего расширяемого функционала
     
  14. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    @MouseZver, но если все классы лежат в одной директории распиханные по папкам с именами своих namespace разве не достаточно одной функции автолоада?
     
  15. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.799
    Симпатии:
    1.331
    Адрес:
    Лень
    в моем коде их сколько ?o_O
     
  16. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Тогда зачем класс? Как его функционал расширяется?
     
  17. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.799
    Симпатии:
    1.331
    Адрес:
    Лень
    9 и 13 строками
     
  18. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    @MouseZver, Я делаю так:
    - есть в public директории файл config.php в нем строчки
    PHP:
    1. define('FILES', '/home/бла-бла-бла/files/');
    2.  
    3. spl_autoload_register(function ($some_class) {
    4.     $some_path = preg_replace('{^\/}', '', strtolower(str_replace('\\', '/', $some_class)));
    5.     require_once(FILES . 'engin/' . $some_path . '.class.php');
    6. });
    - есть три точки входа index.php, ajax.php и get_photo.php
    - в точках входа реквирю config.php
    - далее нужно заботиться только о пространствах имен, местоположении и именах самих файлов классов и забыть про автолоад

    Чем этот метод хуже? Я реально не знаю. Без подвоха. Прошу объяснить зачем нужна регистрация классов в отдельный массив?
     
  19. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.799
    Симпатии:
    1.331
    Адрес:
    Лень
    тем что ты не сможешь отвязать от пространств и директории. Может класс вовсе лежит в корневом каталоге сайта, но пространство у него совсем другое.

    использование функций preg_replace strreplace
    + подключение через require_once - "у тебя ошибку должно выдавать" = Не гуд.
    --- Добавлено ---
    не нужна, а возможность - приоритет не слишком велик. Если не зарегистрировано пространство, то оно используется как путь к классу
    --- Добавлено ---
    допустим наш класс лежит в папке Application/CMain.php
    Пространство у него App; class: Main
    PHP:
    1. $A = new \App\Main;
    Коротко и ясно
    --- Добавлено ---
    PHP:
    1. [ 'App\Main' => 'Application\CMain' ]
    --- Добавлено ---
    Пространство(Любое) => директория
     
  20. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Я не использую другие директории. Все пространства имен совпадают с именами папок.
    Про replace понятно, но не критично.
    С include, как раз тоже будет ошибка если класс так и не будет инициализирован. Если использовать больше одной функции, то тут include - я согласен.

    Как я понял подобный класс удобен если есть несколько разных директорий для классов не связанных именами с пространством имен?
     
  21. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.799
    Симпатии:
    1.331
    Адрес:
    Лень
    Каждому свое какой рукой любить.

    Ты о чем ?
     
  22. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Я о том что есть стек автолоад-функций. Если функций больше чем одна, а нужный файл загрузит не первая функция, тогда require остановит выполнение кода. Если она одна, как в моем случае, то require выдаст ошибку, что файл не найден, а с include будет фатальная ошибка, если файл с классом не найдется и класс не будет инициализирован. В моем случае include и require одинаково отработают. Будет только разница в логах ошибок.
     
  23. Danil005

    Danil005 Активный пользователь

    С нами с:
    2 янв 2015
    Сообщения:
    528
    Симпатии:
    30
    @MouseZver. почему-то я сделал так:

    Структура:
    -Application
    --C.Application.php
    index.php
    namespace.php

    namespace.php:
    PHP:
    1. <?php
    2.  
    3. namespace Aero
    4. {
    5.     class AeroBase
    6.     {
    7.  
    8.         protected static $NAMESPACESMAP = [
    9.             App\Application::class => 'Application\C.Application'
    10.         ];
    11.  
    12.         public static function setPatchMap( string $NAME, string $PATCH )
    13.         {
    14.             self::$NAMESPACESMAP[$NAME] = $PATCH;
    15.         }
    16.         public static function autoload( $CLASS )
    17.         {
    18.             if (1)
    19.             {
    20.                 echo "{$CLASS}<br>" . PHP_EOL;
    21.             }
    22.      
    23.             if ( isset ( self::$NAMESPACESMAP[$CLASS] ) )
    24.             {
    25.                 $CLASS = self::$NAMESPACESMAP[$CLASS];
    26.             }
    27.      
    28.             include dirname ( __FILE__ ) . DIRECTORY_SEPARATOR . strtr ( $CLASS, '\\', DIRECTORY_SEPARATOR ) . '.php';
    29.         }
    30.     }
    31. }
    32. namespace
    33. {
    34.     spl_autoload_register ( [ \Aero\AeroBase::class, 'autoload' ] );
    35. }
    C.Application.php:

    PHP:
    1. <?php
    2.  
    3. namespace Aero\App;
    4.  
    5. class Application
    6. {
    7.   public function p() {
    8.       echo "1";
    9.   }
    10. }
    index.php
    PHP:
    1. <?php include('namespace.php');
    2.  
    3.  
    4. App\Application::p();
    --- Добавлено ---
    Все равно ошибки:

    Warning: include(E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\App\Application.php): failed to open stream: No such file or directory in E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\namespace.php on line 29

    Warning: include(): Failed opening 'E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\App\Application.php' for inclusion (include_path='.;e:/server/openserver/modules/php/PHP-7;e:/server/openserver/modules/php/PHP-7/PEAR/pear') in E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\namespace.php on line 29

    Fatal error: Uncaught Error: Class 'App\Application' not found in E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\index.php:4 Stack trace: #0 {main} thrown in E:\Server\OpenServer\domains\zagotovkis.ru\load_class_namespace\index.php on line 4
     
  24. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.799
    Симпатии:
    1.331
    Адрес:
    Лень
    ой впизду объяснять по 100 раз
     
    AlexProg нравится это.