RizVN Login



PHP - Почему надо быть осторожным с автозагрузкой классов?

PHP - Почему надо быть осторожным с автозагрузкой классов?В рамках данной статьи, я расскажу вам почему необходимо быть осторожным с автозагрузкой классов в PHP и какие проблемы могут возникнуть.

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

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

Начну с простых проблем. В PHP существует возможность определить функцию __autoload, которая вызывается в том случае, если вы пытаетесь создать экземпляр класса, который до этого не был определен. Тем самым у вас появляется возможность динамически подключать файлы, например, из директорий аля "includes". Выглядит это примерно так (функция сильно упрощена):

function __autoload($class_name) {
    require_once '/includes/' . $class_name . '.php';
}

Удобная конструкция, не правда ли? Конечно, когда речь идет о коде только из вашего проекта. Дело в том, что такая функция может быть определена только один раз. А это значит, что если вам потребуется подключить какие-то сторонние библиотеки, где так же использовалась подобная функция, то вам придется разгребать код библиотек и пытаться две функции соединить. Не сложно догадаться, что подключив десяток другой таких библиотек, проблем станет больше.

Примечание: Эта проблема касается не только сторонних библиотек. Банально, если ваш собственный код разрастется, то все подключения необходимо осуществлять все в одной функции.

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

Разберем один пример. Допустим, в зависимости от post параметров вы создаете классы. И в этом ничего страшного нет. Однако, в одно время вы так же создали класс Test для тестирования одной из ситуаций. Для простоты в этот класс так же запихнули код для повышения привилегий. Протестировав все, что нужно, вы просто закомментировали строчку с вызовом класса.

Класс test:

// некий код Test.php в каталоге includes
// Запрещаем прямой вызов
if (!defined('MEGA_SITE')) {
    die();
}
class Test
{
//... Некий код
}
// Установка админских прав
$is_admin = 1;

Файл index.php:

// Определяем константу для закрытия вызова внутренних классов
define('MEGA_SITE', 1);
// Функция автоподгрузки
function __autoload($class_name) {
    require_once '/includes/' . $class_name . '.php';
}
// ... Выполнение неких действий
// Если в посте указан класс
 if (isset($_POST['class'])) {
// Получаем имя класса
$class_name = $_POST['class'];
// Задокументированная часть для тестирования
// $obj = new Test();
// Создаем объект класса
$obj = new $class_name();
}
// ... Выполнение неких действий

Конечно, это не самый лучший метод создания классов, но структурно оно выглядит примерно так. Не сложно догадаться, что стоит передать в $_POST['class'] имя Test, как будут получены администраторские права к сайту. Конечно, в зависимости от кода это может мало чего дать злоумышленнику, но и приятного в этом ничего нет.

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

Начиная с 5.1.2 версии PHP появилась поддержка более расширенной вариации автозагрузчика. Теперь, это все реализуется в виде стека функций автозагрузки. Простыми словами, при помощи функции spl_autoload_register вы легко можете добавлять свои функции для осуществления автозагрузки.

Действует это простейшим образом. При попытке создать экземпляр ранее неизвестного класса, PHP будет по очереди вызывать функции (в порядке их добавления) и если класс для создания стал доступен после вызова какой-то из функций, то загрузчик прекратит вызывать функции автозагрузки. В целом, звучит это все здорово. Но, все же есть нюансы.

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

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

1 1 1 1 1 1 1 1 1 1 Рейтинг 5.00 (1 Голос)

Комментарии / отзывы   

0 # Rjlth 21.08.2017 16:26
Понравилось про тестовый класс. Всякая фигня после объявления класса - нередкая ошибка.
Ответить | Ответить с цитатой | Цитировать | Сообщить модератору

Добавить комментарий / отзыв

Комментарий - это вежливое и наполненное смыслом сообщение (правила).


Введите защитный код

Обновить
Защитный код

Каталог программ