Как обработать включение необходимых классов в PHP

StackOverflow https://stackoverflow.com/questions/23802

  •  09-06-2019
  •  | 
  •  

Вопрос

Мне интересно, какова наилучшая практика для решения проблемы с необходимостью "включать" так много файлов в мои PHP-скрипты, чтобы гарантировать, что все классы, которые мне нужно использовать, доступны для моего скрипта.

В настоящее время я просто использую включение_once чтобы включить классы, к которым я обращаюсь напрямую.Каждый из них будет include_once классы, к которым они обращаются.

Я изучил возможность использования __autoload функция, но, похоже, hat работает не очень хорошо, если вы планируете организовать файлы вашего класса в виде дерева каталогов.Если бы вы сделали это, похоже, что в конечном итоге вам пришлось бы бродить по дереву каталогов, пока вы не нашли класс, который вы искали. Кроме того, я не уверен, как это влияет на классы с одинаковыми именами в разных пространствах имен.

Есть ли более простой способ справиться с этим?

Или PHP просто не подходит для "предприимчивый" введите приложения с большим количеством различных объектов, расположенных в отдельных файлах, которые могут находиться во множестве разных каталогов.

Это было полезно?

Решение

I мои приложения, которые у меня обычно есть setup.php файл, содержащий все основные классы (т. е.фреймворк и сопутствующие библиотеки).Мои пользовательские классы загружаются с помощью автозагрузчика, поддерживаемого картой расположения каталогов.

Каждый раз, когда добавляется новый класс, я запускаю скрипт командной строки builder, который сканирует все дерево каталогов в поисках классов моделей, затем создает ассоциативный массив с именами классов в качестве ключей и путями в качестве значений.Затем функция __autoload ищет имя класса в этом массиве и получает путь включения.Вот код:

autobuild.php

define('MAP', 'var/cache/autoload.map');
error_reporting(E_ALL);
require 'setup.php';
print(buildAutoloaderMap() . " classes mapped\n");

function buildAutoloaderMap() {
    $dirs = array('lib', 'view', 'model');
    $cache = array();
    $n = 0;
    foreach ($dirs as $dir) {
        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $entry) {
            $fn = $entry->getFilename();
            if (!preg_match('/\.class\.php$/', $fn))
                continue;
            $c = str_replace('.class.php', '', $fn);
            if (!class_exists($c)) {
                $cache[$c] = ($pn = $entry->getPathname());
                ++$n;
            }
        }
    }
    ksort($cache);
    file_put_contents(MAP, serialize($cache));
    return $n;
}

autoload.php

define('MAP', 'var/cache/autoload.map');

function __autoload($className) {
    static $map;
    $map or ($map = unserialize(file_get_contents(MAP)));
    $fn = array_key_exists($className, $map) ? $map[$className] : null;
    if ($fn and file_exists($fn)) {
        include $fn;
        unset($map[$className]);
    }
}

Обратите внимание, что соглашение об именовании файлов должно быть [имя_класса].class.php .Измените каталоги, в которых будут просматриваться классы autobuild.php.Вы также можете запустить autobuilder из функции автозагрузки, когда класс не найден, но это может привести вашу программу к бесконечному циклу.

Сериализованные массивы работают чертовски быстро.

@Джейсон Майкл:PHP 4 мертв.Смирись с этим.

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

Вы можете определить несколько функций автоматической загрузки с помощью spl_autoload_register:

spl_autoload_register('load_controllers');
spl_autoload_register('load_models');

function load_models($class){
    if( !file_exists("models/$class.php") )
        return false;

    include "models/$class.php";
    return true;
}
function load_controllers($class){
    if( !file_exists("controllers/$class.php") )
        return false;

    include "controllers/$class.php";
    return true;
}

Вы также можете программно определить местоположение файла класса, используя структурированные соглашения об именовании, которые сопоставляются физическим каталогам.Вот как Zend делает это в Фреймворк Zend.Поэтому, когда ты позвонишь Zend_Loader::loadClass("Zend_Db_Table"); он преобразует classname в массив каталогов путем разделения по символам подчеркивания, а затем класс Zend_Loader загружает требуемый файл.

Как и все модули Zend, я ожидал бы, что вы можете использовать только загрузчик сам по себе с вашими собственными классами, но я использовал его только как часть сайта, использующего MVC от Zend.

Но были опасения по поводу производительности при загрузке, когда вы используете какой-либо вид динамической загрузки класса, например, см. это сообщение в блоге сравнение Zend_Loader с жесткой загрузкой файлов классов.

Помимо снижения производительности из-за необходимости поиска пути включения PHP, это приводит к сбою кэширования кода операции.Из комментария к этому сообщению:

При использовании ЛЮБОГО загрузчика динамических классов APC не может полностью кэшировать эти файлы, поскольку не уверен, какие файлы будут загружены при любом отдельном запросе.При жесткой загрузке файлов APC может кэшировать их полностью.

__autoload работает хорошо, если у вас есть согласованное соглашение об именовании для ваших классов, которое сообщает функции, где они находятся внутри дерева каталогов.MVC особенно хорошо подходит для такого рода задач, потому что вы можете легко разделить классы на модели, представления и контроллеры.

В качестве альтернативы, сохраните ассоциативный массив имен для расположения файлов для вашего класса и позвольте __autoload запросите этот массив.

Из предложенных на данный момент предложений я неравнодушен к предложению Кевина, но оно не обязательно должно быть абсолютным.Я вижу пару различных вариантов для использования с __автозагрузкой.

  1. Поместите все файлы класса в один каталог.Назовите файл в честь класса, т.е., classes/User.php или classes/User.class.php.
  2. Идея Кевина поместить модели в один каталог, контроллеры - в другой и т.д.Работает хорошо, если все ваши классы хорошо вписываются в MVC framework, но иногда все становится беспорядочным.
  3. Включите каталог в имя_класса.Например, класс с именем Model_User на самом деле был бы расположен по адресу classes/Model/User.php.Ваша функция __autoload будет знать, как преобразовать символ подчеркивания в разделитель каталогов, чтобы найти файл.
  4. Просто проанализируйте всю структуру каталогов один раз.Либо в функции __autoload, либо даже просто в том же PHP-файле, где она определена, выполните цикл по содержимому classes каталогизируйте и кэшируйте, какие файлы где находятся.Итак, если вы попытаетесь загрузить User класс, не имеет значения, находится ли он в classes/User.php или classes/Models/User.php или classes/Utility/User.php.Как только он найдет User.php где-то в classes каталог, он будет знать, какой файл включить, когда User класс должен быть загружен автоматически.

@Кевин:

Я просто пытался указать, что spl_autoload_register является лучшей альтернативой __autoload, поскольку вы можете определить несколько загрузчиков, и они не будут конфликтовать друг с другом.Удобно, если вам нужно включить библиотеки, которые также определяют функцию __autoload.

Вы уверены?Тот Самый Документация говорит по - другому:

Если в вашем коде есть существующая функция __autoload, то эта функция должна быть явно зарегистрирована в стеке __autoload.Это связано с тем, что функция spl_autoload_register() эффективно заменит кэш ядра для функции __autoload либо на spl_autoload(), либо на spl_autoload_call().

=> вы должны явно зарегистрировать любую библиотеку __autoload также хорошо.Но в остальном вы, конечно, правы, эта функция - лучшая альтернатива.

__autoload будет работать, но только в PHP 5.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top