Насколько уникален PHP __autoload()?
PHP __autoload()
(документация) мне очень интересна. Вот как это работает:
- Вы пытаетесь использовать класс, например
new Toast_Mitten()
(footnote 1)
- Класс не загружен в память. PHP откидывает кулак, чтобы выбить вас с ошибкой.
- Он останавливается. "Подождите, - говорит он." Там определена функция
__autoload()
". Он запускает его.
- В этой функции вы каким-то образом сопоставили строку
Toast_Mitten
с classes/toast_mitten.php
и сказали ей, что требуется этот файл. Он делает.
- Теперь класс находится в памяти, и ваша программа продолжает работать.
Преимущество памяти: вы загружаете только нужные классы. Преимущество терминологии: вы можете остановить включение большого количества файлов во всем мире и просто включить свой автозагрузчик.
Все становится особенно интересным, если
1) Ваш __autoload()
имеет автоматический способ определения пути и имени файла из имени класса. Например, возможно, все ваши классы находятся в classes/
и Toast_Mitten
будут в classes/toast_mitten.php
. Или, возможно, вы называете такие классы, как Animal_Mammal_Weasel
, который будет находиться в classes/animal/mammal/animal_mammal_weasel.php
.
2) Вы используете метод factory для получения экземпляров вашего класса.
$Mitten = Mitten::factory('toast');
Метод Mitten:: factory может сказать себе: "Посмотрим, у меня есть подкласс, называемый Toast_Mitten()
? Если это так, я верну его, а если нет, я просто верну общий пример о себе, стандартная рукавица. О, посмотри! __autoload()
говорит мне, что есть специальный класс для тостов. ОК, вот экземпляр!"
Таким образом, вы можете начать использовать универсальную рукавицу во всем своем коде, и когда наступит день, вам нужно специальное поведение для тоста, вы просто создаете этот класс и bam! - ваш код использует он.
Мой вопрос двоякий:
- (Факт) Имеют ли другие языки подобные конструкции? Я вижу, что Ruby имеет автозагрузку, но, похоже, вам нужно указать в заданном script, какие классы вы планируете использовать.
- (Мнение) Является ли это слишком волшебным? Если ваш любимый язык не делает этого, вы думаете: "Эй, изящный, мы должны иметь это" или "человек, я рад, что язык X не такой неряшливый?"
1 Приношу свои извинения не англоязычным докладчикам. Это небольшая шутка. Насколько я знаю, нет такой вещи, как "топиная рукавица". Если бы это было так, это была бы рукавица для сбора горячего тоста. Возможно, у вас есть тосты в вашей родной стране?
Ответы
Ответ 1
И Ruby, и PHP получают его от AUTOLOAD в Perl.
Обратите внимание, что модуль AutoLoader представляет собой набор помощников для общих задач с использованием функций AUTOLOAD.
Ответ 2
- Не используйте
__autoload()
. Это глобальная вещь, поэтому, по определению, она несколько зла. Вместо этого используйте spl_autoload_register()
, чтобы зарегистрировать еще один автозагрузчик в вашей системе. Это позволяет использовать несколько автозагрузчиков, что довольно распространенная практика.
- Уважать существующие соглашения. Каждая часть имени класса с именами имен является каталогом, поэтому
new MyProject\IO\FileReader();
должен находиться в файле MyProject/IO/FileReader.php
.
-
Магия - это зло!
Метод Mitten:: factory может сказать себе: "Посмотрим, у меня есть подкласс под названием Toast_Mitten()? Если это так, я верну его, а если нет, я просто верну общий пример __autoload() говорит мне, что есть специальный класс для тостов. ОК, вот экземпляр!"
Скорее такой хитрый код, используйте простой и подробный:
try {
$mitten = new ToastMitten();
// or $mitten = Mitten::factory('toast');
} catch (ClassNotFoundException $cnfe) {
$mitten = new BaseMitten();
}
Ответ 3
Я думаю, что эта функция очень удобна, и я не видел никаких функций, подобных ей. Мне также не нужны эти функции еще где.
Ответ 4
Java имеет нечто подобное. Он назывался ClassLoader
. Возможно, другие языки тоже, но они придерживаются некоторой реализации по умолчанию.
И, пока мы в этом. Было бы неплохо, если бы __autoload
загружал любые типы символов, а не только классы: константы, функции и классы.
Ответ 5
См. Ruby Module # const_missing
Я только что узнал об этом: Ruby имеет метод в модуле с именем const_missing
, который вызывается, если вы вызываете Foo::Bar
и Bar
еще не в памяти (хотя я полагаю, что Foo
должен быть в памяти).
Этот пример в ruby-doc.org показывает способ использования этого для реализации автозагрузчика для этого модуля. Это, по сути, то, что Rails использует для загрузки новых классов модели ActiveRecord в соответствии с "Eloquent Ruby" Руса Олсена (глава 21, "Использовать метод_изменение для гибкой обработки ошибок", который также охватывает const_missing
).
Он может сделать это из-за мышления "соглашение над конфигурацией": если вы ссылаетесь на модель под названием ToastMitten
, если она существует, она будет находиться в app/models/toast_mitten.rb
. Если бы вы могли разместить эту модель в любом месте, которое вы хотели, Rails не знал бы, где ее искать. Даже если вы не используете Rails, этот пример и пункт №1 в моем вопросе показывают, насколько полезно использовать следующие соглашения, даже если вы создаете их самостоятельно.