За последние 24 часа нас посетили 17763 программиста и 1711 роботов. Сейчас ищут 1629 программистов ...

Обсуждаем __autoload()

Тема в разделе "Решения, алгоритмы", создана пользователем Hight, 11 май 2008.

  1. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Вот моя реализация:
    PHP:
    1.  
    2. <?php
    3.  
    4. header('Content-Type: text/html;charset=utf-8');
    5.  
    6. define('ROOT_PATH', './');
    7. define('CLASSES_DIR', ROOT_PATH.'classes');
    8.  
    9. // Сканирует директорию с классами
    10. function autoload_scan_dirs($dir)
    11. {
    12.     global $AUTOLOAD_CLASSES_LIST;
    13.  
    14.     if($handle = opendir($dir))
    15.     {
    16.         while(false !== ($file = readdir($handle)))
    17.         {
    18.             if($file != '.' and $file != '..')
    19.             {
    20.                 if(is_dir($path = $dir.'/'.$file))
    21.                 {
    22.                     autoload_scan_dirs($path);
    23.                 }
    24.                 else
    25.                 {
    26.                     $AUTOLOAD_CLASSES_LIST[][$dir] = $file;
    27.                 }
    28.             }
    29.         }
    30.  
    31.         closedir($handle);
    32.     }
    33. }
    34.  
    35.  
    36. // Загружает класс
    37. function __autoload($class_name)
    38. {
    39.     global $AUTOLOAD_CLASSES_LIST;
    40.  
    41.     if(!isset($AUTOLOAD_CLASSES_LIST)) autoload_scan_dirs(CLASSES_DIR);
    42.  
    43.     foreach($AUTOLOAD_CLASSES_LIST as $index => $class_array)
    44.     {
    45.         if(in_array($class_name.'.php', $class_array))
    46.         {
    47.             foreach($class_array as $class_path => $class_name)
    48.             {
    49.                 if(file_exists($class = $class_path.'/'.$class_name))
    50.                 {
    51.                     require_once($class);
    52.                 }
    53.                 else
    54.                 {
    55.                     trigger_error('Error. Function: __autoload(). Class "'.$class_name.'" not found.', E_USER_ERROR);
    56.                 }
    57.             }
    58.         }
    59.     }
    60. }
    61.  
    62.  
    63. $hight = new hight;
    64. $hight -> show();
    65.  
    66. /*$test = new test;
    67. $test -> show();*/
    68.  
    69. echo'<pre>';
    70. print_r($AUTOLOAD_CLASSES_LIST);
    71. echo'</pre>';
    72.  
    73. ?>
    74.  
    А вот теперь внимание вопрос =) В связи с переутомлением, не перемудрил ли я? Всё ли корректно? У меня вроде всё работает, но может я лабуду написал?

    А так же выкладывайте сюда свои реализации ;) Интересно обсудить.
     
  2. Anonymous

    Anonymous Guest

    PHP:
    1. <?php
    2. function __autoload($classname)
    3.     {
    4.         include_once('classes/'.$classname.'.class.php');
    5.     }
    6. ?>
    Мне хватает )
     
  3. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Я сначала тоже так хотел сделать. Но почему-то сделал по-другому =) Вечером уберу функцию "autoload_scan_dirs". Перенесу её логику в автолоад.
     
  4. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    PHP:
    1.  
    2. <?php
    3.  
    4. /**
    5. * Автозагрузчик классов
    6. *
    7. * Используется для автоматической загрузки классов в код
    8. *
    9. * @package      Indigo
    10. * @subpackage   Core
    11. *
    12. * @author     Andrey Lugovoy <root@440hz.ru>
    13. * @version    $Id: autoload.php  $
    14. * @copyright 2007 (c) 440hz
    15. *
    16. * @access public
    17. *
    18. */
    19.  
    20. /**
    21. * получаем список директориев для сканирования
    22. */
    23. function autoloadscandirs($dir,&$dirs) {
    24.  
    25.     if (is_dir($dir)) {
    26.         $dirs[] = $dir;
    27.         if ($dh = opendir($dir)) {
    28.             while (($file = readdir($dh)) !== false) {
    29.                 if($file[0] == '.') continue;
    30.                 $filename = $dir.$file;
    31.                 if(is_dir($filename)) autoloadscandirs($filename.'/',$dirs);
    32.             }
    33.             closedir($dh);
    34.         }
    35.     }
    36.  
    37.  
    38.  
    39.  
    40. }
    41.  
    42. /**
    43. * получаем список файлов для сканирования
    44. */
    45. function autoloadscanfiles($dir,&$dirs) {
    46.  
    47.     if (is_dir($dir)) {
    48.         if ($dh = opendir($dir)) {
    49.             while (($file = readdir($dh)) !== false) {
    50.                 if($file[0] == '.') continue;
    51.                 $filename = $dir.$file;
    52.                 if(is_dir($filename)) autoloadscanfiles($filename.'/',$dirs);
    53.                 if(is_file($filename))     
    54.                     $dirs[] = $file;
    55.  
    56.             }
    57.             closedir($dh);
    58.         }
    59.     }
    60.  
    61.  
    62.  
    63.  
    64. }
    65.  
    66. /**
    67. *
    68. * Автозагрузчик
    69. *
    70. * @param $name string
    71. * @return bool
    72. * @access public
    73. */
    74. function __autoload($name) {
    75.  
    76.     static $dirs = false;
    77.  
    78.     if(!$dirs) autoloadscandirs(INDIGO_CLASS_ROOT.'/',$dirs);
    79.  
    80.     // получмили имя класса
    81.     $name = strtolower(basename($name)).'.php';
    82.  
    83.     foreach($dirs AS $dir) {
    84.         $filename = $dir.$name;
    85.         if(file_exists($filename)) {
    86.             require_once($filename);
    87.             return true;
    88.         }
    89.     }
    90.  
    91.     die("не могу загрузить класс [$name]");
    92.  
    93.     return false;
    94.  
    95. }
    96.  
    97. ?>
    можно поизвращаться с именами файлов, но это уже дело кадого.

    empty.php
    class.empty.inc
    empty.class.php

    и т.д.
     
  5. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    имхо нечего список диров и файлов хранить в глобале.
    рекомендовано в статик и в самой функции ибо больше нее это никому нах не нужно.

    так же можно сразу грузить связку класс->файл и потом только в массиве искать. мне лениво было переписывать. честно. он по уму надо.
     
  6. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    по уму - не надо при каждом запуске сприпта сканировать директории и уж тем более делать это при каждом запросе класса.
    это пустая трата ресурсов.
     
  7. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    тут оооочень тонкое политическое место. надо основательно посидеть и подумать надо ли тебе такое (каждый раз сканировать).

    я полностью согласен что в некоторых проектах такое расточительство НЕ допустимо.

    а в некоторых не особопосещаемых как раз самое то. с учетом скорости разработки и т.д.

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

    p.s. при достаточно большом объеме классов ручная загрузка может превратиться в рутину.

    -------

    ну и собственно тесты.
    такое (__autoload) работает и нижжужит при 150000 хостов в день.
    время ген. страницы 0.03-0.1.
    так что можно и не париться.......
    ггг
     
  8. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    ну да, такая прям рутина...

    PHP:
    1. $db= new My_DB_MySql( $dsn );
    или
    PHP:
    1. $db= onc( 'db/mysql' )->create( $dsn );
     
  9. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Ну при каждом проходе скрипта не напрягает сканировать, а каждый раз при вызове функции никто и не сканирует. Сейчас переделаю свой автолоад на светлую голову.
     
  10. lexa

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

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    У мну так:
    Код (Text):
    1. $db = new My_DB_MySql($dsn);
    ищет (по приоритету): My/DB/MySql.php, My_DB_MySql/My_DB_MySql.php или My_DB_MySql.php. Всё в одной папке. Вот думаю только, много static + include быстрее ли, чем нынешний include_once.
     
  11. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Остановился на таком варианте:
    PHP:
    1. <?php error_reporting(E_ALL);
    2.  
    3. header('Content-Type: text/html;charset=utf-8');
    4.  
    5. define('ROOT_PATH', './');
    6. define('CLASSES_DIRS', 'classes:drupal');
    7.  
    8.  
    9. function autoload_scan_dirs($dirs_str, &$classes_list)
    10. {
    11.     $dirs_array = explode(':', $dirs_str);
    12.  
    13.     foreach($dirs_array as $index => $dir)
    14.     {
    15.         if(!$handle = @opendir(ROOT_PATH.$dir)) trigger_error('Error. Function: autoload_scan_dirs(). Failed to open "'.ROOT_PATH.$dir.'".', E_USER_ERROR);
    16.         {
    17.             while(false !== ($file = readdir($handle)))
    18.             {
    19.                 if($file != '.' and $file != '..')
    20.                 {
    21.                     if(is_dir(ROOT_PATH.$path = $dir.'/'.$file))
    22.                     {
    23.                         autoload_scan_dirs($path, $classes_list);
    24.                     }
    25.                     else
    26.                     {
    27.                         $classes_list[][ROOT_PATH.$dir] = $file;
    28.                     }
    29.                 }
    30.             }
    31.  
    32.             closedir($handle);
    33.         }
    34.     }
    35. }
    36.  
    37.  
    38. function __autoload($class_name)
    39. {
    40.     static $classes_list = false;
    41.  
    42.     if(!$classes_list) autoload_scan_dirs(CLASSES_DIRS, $classes_list);
    43.  
    44.     $class_found = false;
    45.  
    46.     foreach($classes_list as $index => $class_array)
    47.     {
    48.         if($class_path = array_search('class.'.$class_name.'.php', $class_array, true))
    49.         {
    50.             $class_found = true;
    51.  
    52.             if(file_exists($class = $class_path.'/class.'.$class_name.'.php'))
    53.             {
    54.                 require_once($class);
    55.             }
    56.             else
    57.             {
    58.                 trigger_error('Error. Function: __autoload(). Class "'.$class_name.'" not found.', E_USER_ERROR);
    59.             }
    60.         }
    61.     }
    62.  
    63.     if(!$class_found) trigger_error('Error. Function: __autoload(). Class "'.$class_name.'" not found.', E_USER_ERROR);
    64. }
    65.  
    66.  
    67. $obj1 = new hight;
    68.  
    69. $obj2 = new test;
    70.  
    71. ?>
    Теперь можно много папок сканировать.
    Имена файлов классов вида: class.name.php
    define('CLASSES_DIRS', 'classes:drupal'); - Через двоеточие перечисляем папки для сканирования отностительно ROOT_PATH
     
  12. sword dancer

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

    С нами с:
    17 фев 2008
    Сообщения:
    295
    Симпатии:
    0
    магия в программировании - зло.
     
  13. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Hight
    А почему бы не использовать glob('*') и потом не бегать по уже готовому массиву? :)
     
  14. Ti

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

    С нами с:
    3 июл 2006
    Сообщения:
    2.378
    Симпатии:
    1
    Адрес:
    d1.ru, Екатеринбург
    1. разумнее использовать spl_autoload_register

    2. если все классы лежат в одной дирректории, вариант Олега проще, понятней, изящней...
    Единственная проблема, если зарегистрированно много autoload'еров код не должен давать ошибок при отсутствии класса (он может подружаться другим методом)

    3. много букв, global плохо
    можно реализовать ввиде класса:
    PHP:
    1. <?
    2. class MyClassLoader {
    3.     static function Register() {
    4.         spl_autoload_register(array(new self, 'loadClass'));
    5.     }
    6.  
    7.  
    8.     function loadClass() {
    9.         // ...
    10.     }
    11.     // ...
    12. }
     
  15. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Использую.
    Я люблю извращения. Могу положить файлы классов в соответствующие папки =)
    Нету глобала уже.
    Мысль!
    Ни разу не использовал. Посмотрю.
     
  16. Volk_88

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

    С нами с:
    14 июн 2009
    Сообщения:
    2
    Симпатии:
    0
    Приветствую всех!
    У меня вопрос относительно spl_autoload_register.

    Допустим есть кусок кода:

    PHP:
    1. function hello(){
    2.         print "Hello";
    3. }
    Не логично ли было вывести на экран слово: Hello ?
    Или я что то не понял в действии данной функции...

    сорри, если ламерский вопрос :)
     
  17. Ну, мотивируй, откуда у тебя возникла в голове такая логика относительно написанного в документации?
     
  18. Volk_88

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

    С нами с:
    14 июн 2009
    Сообщения:
    2
    Симпатии:
    0
    легко, надо меньше сидеть за компом и больше отдыхать :(
    это я перпутал с call_user_func

    сорри, за действительно ламерский вопрос)
     
  19. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    Мастер-дзен. А у меня на "MVC" порядка 0.1 с при практически пустом контенте...
     
  20. AlexGousev

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

    С нами с:
    25 мар 2006
    Сообщения:
    1.505
    Симпатии:
    0
    Адрес:
    Москва
    Ничего… какой-нибудь drupal еще ничего не вывел, а уже сделал сотню запросов :)
     
  21. Elkaz

    Elkaz Старожил
    Команда форума Модератор

    С нами с:
    26 июн 2006
    Сообщения:
    3.373
    Симпатии:
    0
    Адрес:
    Баку, Азербайджан
    PHP:
    1.  
    2. <?php
    3. public function __autoload(){
    4.         if (!is_dir ($this->ClassDirectory)){
    5.             throw new ClassException ('Class directory does not exists');
    6.         } else {
    7.             $List = glob ($this->ClassDirectory . '/*.class.php');
    8.             $Count = count ($List);
    9.             if ($Count > 0){
    10.                 foreach ($List as $ClassFile){
    11.                     include ($ClassFile);
    12.                 }
    13.             }
    14.         }
    15.     }
    16. ?>
    17.  
     
  22. kostyl

    kostyl Guest

    PHP:
    1.  
    2. <?php
    3. define('ROOT_PATH', './');
    4. define('CLASSES_PATH', ROOT_PATH . 'classes/');
    5. define('PHP_EXT', '.php');
    6. function __autoload($sClassName)
    7. {
    8.     require_once CLASSES_PATH . $sClassName . PHP_EXT;
    9. }
    По-моему, большего не нужно... Зачем нужны огороды со
    Код (Text):
    1. ...scan_dirs...
    ?
     
  23. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Нужны, чтобы файлы классов можно было по папкам раскидать. Кому-то это не нужно, а кому-то нужно. Вот меня такое решение радует.
     
  24. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    Для меня, если честно, тоже непонятно:
    PHP:
    1. <?php
    2. // Autoload
    3.     function __autoload($className) {
    4.         $class = ENGINE_PATH . 'Classes/' . str_replace('_', '/', $className) . '.php';
    5.         if(is_file($class)) {
    6.             require_once $class;
    7.         }
    8.     }
     
  25. kostyl

    kostyl Guest

    TheShock
    Просто классы необходимо будет группировать, станет понятно ;)