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

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

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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать 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 и хотите разрабатывать...
3
0
2 994
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

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

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

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

Вы можете определить несколько функций автозагрузки с 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;
}

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

  1. Поместите все файлы классов в один каталог. Назовите файл по классу, например classes/User.php или classes/User.class.php.
  2. Идея Кевина о размещении моделей в одном каталоге, контроллеров в другом и т. д. Хорошо работает, если все ваши классы хорошо вписываются в структуру MVC, но иногда все становится беспорядочно.
  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 должен быть загружен автоматически.

@ Кевин:

I was just trying to point out that spl_autoload_register is a better alternative to __autoload since you can define multiple loaders, and they won't conflict with each other. Handy if you have to include libraries that define an __autoload function as well.

Уверены ли вы? документация говорит иначе:

If your code has an existing __autoload function then this function must be explicitly registered on the __autoload stack. This is because spl_autoload_register() will effectively replace the engine cache for the __autoload function by either spl_autoload() or spl_autoload_call().

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

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

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

Каждый раз, когда добавляется новый класс, я запускаю сценарий построения командной строки, который сканирует все дерево каталогов в поисках классов моделей, а затем создает ассоциативный массив с именами классов в качестве ключей и путями в качестве значений. Затем функция __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 из функции автозагрузки, когда класс не найден, но это может привести вашу программу в бесконечный цикл.

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

@JasonMichael: PHP 4 мертв. Преодолей это.

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

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

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

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

When using ANY Dynamic class loader APC can’t cache those files fully as its not sure which files will load on any single request. By hard loading the files APC can cache them in full.

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