Вот моя реализация: PHP: <?php header('Content-Type: text/html;charset=utf-8'); define('ROOT_PATH', './'); define('CLASSES_DIR', ROOT_PATH.'classes'); // Сканирует директорию с классами function autoload_scan_dirs($dir) { global $AUTOLOAD_CLASSES_LIST; if($handle = opendir($dir)) { while(false !== ($file = readdir($handle))) { if($file != '.' and $file != '..') { if(is_dir($path = $dir.'/'.$file)) { autoload_scan_dirs($path); } else { $AUTOLOAD_CLASSES_LIST[][$dir] = $file; } } } closedir($handle); } } // Загружает класс function __autoload($class_name) { global $AUTOLOAD_CLASSES_LIST; if(!isset($AUTOLOAD_CLASSES_LIST)) autoload_scan_dirs(CLASSES_DIR); foreach($AUTOLOAD_CLASSES_LIST as $index => $class_array) { if(in_array($class_name.'.php', $class_array)) { foreach($class_array as $class_path => $class_name) { if(file_exists($class = $class_path.'/'.$class_name)) { require_once($class); } else { trigger_error('Error. Function: __autoload(). Class "'.$class_name.'" not found.', E_USER_ERROR); } } } } } $hight = new hight; $hight -> show(); /*$test = new test; $test -> show();*/ echo'<pre>'; print_r($AUTOLOAD_CLASSES_LIST); echo'</pre>'; ?> А вот теперь внимание вопрос =) В связи с переутомлением, не перемудрил ли я? Всё ли корректно? У меня вроде всё работает, но может я лабуду написал? А так же выкладывайте сюда свои реализации Интересно обсудить.
PHP: <?php function __autoload($classname) { include_once('classes/'.$classname.'.class.php'); } ?> Мне хватает )
Я сначала тоже так хотел сделать. Но почему-то сделал по-другому =) Вечером уберу функцию "autoload_scan_dirs". Перенесу её логику в автолоад.
PHP: <?php /** * Автозагрузчик классов * * Используется для автоматической загрузки классов в код * * @package Indigo * @subpackage Core * * @author Andrey Lugovoy <root@440hz.ru> * @version $Id: autoload.php $ * @copyright 2007 (c) 440hz * * @access public * */ /** * получаем список директориев для сканирования */ function autoloadscandirs($dir,&$dirs) { if (is_dir($dir)) { $dirs[] = $dir; if ($dh = opendir($dir)) { while (($file = readdir($dh)) !== false) { if($file[0] == '.') continue; $filename = $dir.$file; if(is_dir($filename)) autoloadscandirs($filename.'/',$dirs); } closedir($dh); } } } /** * получаем список файлов для сканирования */ function autoloadscanfiles($dir,&$dirs) { if (is_dir($dir)) { if ($dh = opendir($dir)) { while (($file = readdir($dh)) !== false) { if($file[0] == '.') continue; $filename = $dir.$file; if(is_dir($filename)) autoloadscanfiles($filename.'/',$dirs); if(is_file($filename)) $dirs[] = $file; } closedir($dh); } } } /** * * Автозагрузчик * * @param $name string * @return bool * @access public */ function __autoload($name) { static $dirs = false; if(!$dirs) autoloadscandirs(INDIGO_CLASS_ROOT.'/',$dirs); // получмили имя класса $name = strtolower(basename($name)).'.php'; foreach($dirs AS $dir) { $filename = $dir.$name; if(file_exists($filename)) { require_once($filename); return true; } } die("не могу загрузить класс [$name]"); return false; } ?> можно поизвращаться с именами файлов, но это уже дело кадого. empty.php class.empty.inc empty.class.php и т.д.
имхо нечего список диров и файлов хранить в глобале. рекомендовано в статик и в самой функции ибо больше нее это никому нах не нужно. так же можно сразу грузить связку класс->файл и потом только в массиве искать. мне лениво было переписывать. честно. он по уму надо.
по уму - не надо при каждом запуске сприпта сканировать директории и уж тем более делать это при каждом запросе класса. это пустая трата ресурсов.
тут оооочень тонкое политическое место. надо основательно посидеть и подумать надо ли тебе такое (каждый раз сканировать). я полностью согласен что в некоторых проектах такое расточительство НЕ допустимо. а в некоторых не особопосещаемых как раз самое то. с учетом скорости разработки и т.д. как вариант можно иметь гибрида. т.е. в нуэных местх грузим руккми то, что требуется а оостальное отдаем на откуп. p.s. при достаточно большом объеме классов ручная загрузка может превратиться в рутину. ------- ну и собственно тесты. такое (__autoload) работает и нижжужит при 150000 хостов в день. время ген. страницы 0.03-0.1. так что можно и не париться....... ггг
ну да, такая прям рутина... PHP: $db= new My_DB_MySql( $dsn ); или PHP: $db= onc( 'db/mysql' )->create( $dsn );
Ну при каждом проходе скрипта не напрягает сканировать, а каждый раз при вызове функции никто и не сканирует. Сейчас переделаю свой автолоад на светлую голову.
У мну так: Код (Text): $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.
Остановился на таком варианте: PHP: <?php error_reporting(E_ALL); header('Content-Type: text/html;charset=utf-8'); define('ROOT_PATH', './'); define('CLASSES_DIRS', 'classes:drupal'); function autoload_scan_dirs($dirs_str, &$classes_list) { $dirs_array = explode(':', $dirs_str); foreach($dirs_array as $index => $dir) { if(!$handle = @opendir(ROOT_PATH.$dir)) trigger_error('Error. Function: autoload_scan_dirs(). Failed to open "'.ROOT_PATH.$dir.'".', E_USER_ERROR); { while(false !== ($file = readdir($handle))) { if($file != '.' and $file != '..') { if(is_dir(ROOT_PATH.$path = $dir.'/'.$file)) { autoload_scan_dirs($path, $classes_list); } else { $classes_list[][ROOT_PATH.$dir] = $file; } } } closedir($handle); } } } function __autoload($class_name) { static $classes_list = false; if(!$classes_list) autoload_scan_dirs(CLASSES_DIRS, $classes_list); $class_found = false; foreach($classes_list as $index => $class_array) { if($class_path = array_search('class.'.$class_name.'.php', $class_array, true)) { $class_found = true; if(file_exists($class = $class_path.'/class.'.$class_name.'.php')) { require_once($class); } else { trigger_error('Error. Function: __autoload(). Class "'.$class_name.'" not found.', E_USER_ERROR); } } } if(!$class_found) trigger_error('Error. Function: __autoload(). Class "'.$class_name.'" not found.', E_USER_ERROR); } $obj1 = new hight; $obj2 = new test; ?> Теперь можно много папок сканировать. Имена файлов классов вида: class.name.php define('CLASSES_DIRS', 'classes:drupal'); - Через двоеточие перечисляем папки для сканирования отностительно ROOT_PATH
1. разумнее использовать spl_autoload_register 2. если все классы лежат в одной дирректории, вариант Олега проще, понятней, изящней... Единственная проблема, если зарегистрированно много autoload'еров код не должен давать ошибок при отсутствии класса (он может подружаться другим методом) 3. много букв, global плохо можно реализовать ввиде класса: PHP: <? class MyClassLoader { static function Register() { spl_autoload_register(array(new self, 'loadClass')); } function loadClass() { // ... } // ... }
Использую. Я люблю извращения. Могу положить файлы классов в соответствующие папки =) Нету глобала уже. Мысль! Ни разу не использовал. Посмотрю.
Приветствую всех! У меня вопрос относительно spl_autoload_register. Допустим есть кусок кода: PHP: function hello(){ print "Hello"; } spl_autoload_register('hello'); Не логично ли было вывести на экран слово: Hello ? Или я что то не понял в действии данной функции... сорри, если ламерский вопрос
легко, надо меньше сидеть за компом и больше отдыхать это я перпутал с call_user_func сорри, за действительно ламерский вопрос)
PHP: <?php public function __autoload(){ if (!is_dir ($this->ClassDirectory)){ throw new ClassException ('Class directory does not exists'); } else { $List = glob ($this->ClassDirectory . '/*.class.php'); $Count = count ($List); if ($Count > 0){ foreach ($List as $ClassFile){ include ($ClassFile); } } } } ?>
PHP: <?php define('ROOT_PATH', './'); define('CLASSES_PATH', ROOT_PATH . 'classes/'); define('PHP_EXT', '.php'); function __autoload($sClassName) { require_once CLASSES_PATH . $sClassName . PHP_EXT; } По-моему, большего не нужно... Зачем нужны огороды со Код (Text): ...scan_dirs... ?
Нужны, чтобы файлы классов можно было по папкам раскидать. Кому-то это не нужно, а кому-то нужно. Вот меня такое решение радует.
Для меня, если честно, тоже непонятно: PHP: <?php // Autoload function __autoload($className) { $class = ENGINE_PATH . 'Classes/' . str_replace('_', '/', $className) . '.php'; if(is_file($class)) { require_once $class; } }