Я создал плагин, и, конечно же, я, я хотел пойти с хорошим подходом ОО. Теперь я создал этот класс, а затем чуть ниже создаю экземпляр этого класса:
class ClassName {
public function __construct(){
}
}
$class_instance = new ClassName();
Я предполагаю, что есть более WP способ инициировать этот класс, а потом я наткнулся на людей, которые говорят, что они предпочитают иметь init()
функцию, а не функцию __construct()
. И точно так же я нашел несколько человек, использующих следующий хук:
class ClassName {
public function init(){
}
}
add_action( 'load-plugins.php', array( 'ClassName', 'init' ) );
Что обычно считается лучшим способом создания экземпляра класса WP при загрузке и использования его в качестве глобальной переменной?
ПРИМЕЧАНИЕ. В качестве интересного побочного замечания я заметил, что хотя его register_activation_hook()
можно вызвать изнутри __construct
, его нельзя вызвать изнутри, init()
используя второй пример. Возможно, кто-то мог бы просветить меня по этому вопросу.
Редактировать: Спасибо за все ответы, ясно, что есть довольно много споров о том, как обрабатывать инициализацию внутри самого класса, но я думаю, что в целом есть довольно хороший консенсус, который add_action( 'plugins_loaded', ...);
является лучшим способом на самом деле начать его ...
Редактировать: просто, чтобы запутать вещи, я также видел, как это используется (хотя я сам не использовал бы этот метод, потому что превращение классного ОО в функцию, похоже, побеждало его):
// Start up this plugin
add_action( 'init', 'ClassName' );
function ClassName() {
global $class_name;
$class_name = new ClassName();
}
Ответы:
Хороший вопрос, есть ряд подходов, и это зависит от того, чего вы хотите достичь.
Я часто делаю;
Более подробный пример, появившийся в результате недавних дискуссий по этой самой теме в чате, можно увидеть в этом документе члена WPSE toscho .
Пустой конструктор подход.
Вот выдержка из преимуществ / недостатков, взятых из вышеупомянутой сущности, которая полностью иллюстрирует подход пустого конструктора.
Недостаток, на мой взгляд, является слабым в этом, поэтому это должен быть мой любимый подход, но не единственный, который я использую. Фактически, несколько других тяжеловесов, без сомнения, включатся в эту тему, и вскоре они подойдут к этой теме, потому что есть несколько хороших мнений по этой теме, которые следует озвучить.
примечание: мне нужно найти основной пример из toscho, который провел 3 или 4 сравнения того, как создать экземпляр класса в плагине, который рассматривал плюсы и минусы каждого, который вышеупомянутая ссылка была предпочтительным способом сделать это, но другие примеры хорошо контрастируют с этой темой. Надеюсь, у toscho все еще есть это в файле.Примечание: В ПРМЭ ответа на эту тему с соответствующими примерами и сравнениями. Также лучшее решение, например, класс в WordPress.
источник
update.php
файлом и не является частью обычных действий по умолчанию, на которые следует полагаться, когда речь идет о последовательности событий, которые запускаются во время инициализации, и по этой причине я предпочитаю использовать те крючки, которые применяются, в этом случаеplugins_loaded
. Это то, что я часто называю быстрым снимком того, что происходит при действии . Мое объяснение не является полным во всей полноте.register_activation_hook()
вам нужно вызвать эту функцию до того, какplugins_loaded
действие будет запущено.Прибыв сюда ровно через 2 года после того, как был задан первоначальный вопрос, я бы хотел отметить несколько вещей . (Не проси меня указывать на многое , никогда)
Правильный крюк
Чтобы создать экземпляр класса плагина, необходимо использовать правильный хук. Не существует общего правила, потому что это зависит от того, что делает класс.
Использование очень ранних хуков типа like
"plugins_loaded"
часто не имеет смысла, потому что подобный хук запускается для запросов admin, frontend и AJAX, но очень часто поздний хук гораздо лучше, потому что он позволяет создавать экземпляры классов плагинов только при необходимости.Например, класс, который делает вещи для шаблонов, может быть создан
"template_redirect"
.Вообще говоря, очень редко нужно создавать экземпляр класса до того,
"wp_loaded"
как его уволят.Нет бога класса
Большинство классов, используемых в качестве примеров в более старых ответах, используют класс с именем like
"Prefix_Example_Plugin"
или"My_Plugin"
... Это указывает на то, что, вероятно, существует основной класс для плагина.Хорошо, если плагин не сделан одним единственным классом (в этом случае его имя после имени плагина абсолютно разумно), чтобы создать класс, который управляет всем плагином (например, добавление всех хуков, которые нужны плагину, или создание экземпляров всех других классов плагинов). ) можно считать плохой практикой, как пример объекта бога .
В объектно-ориентированном программном коде, как правило, должен быть твердым, где «S» означает «принцип единой ответственности» .
Это означает, что каждый класс должен делать одну вещь. В разработке плагинов WordPress это означает, что разработчики должны избегать использования единственного хука для создания экземпляра основного класса плагина, но разные хуки должны использоваться для создания экземпляров разных классов в соответствии с ответственностью класса.
Избегайте хуков в конструкторе
Этот аргумент был представлен в других ответах здесь, однако я хочу отметить эту концепцию и связать этот другой ответ, где он довольно широко объясняется в области юнит-тестирования.
Почти 2015: PHP 5.2 для зомби
С 14 августа 2014 года PHP 5.3 достиг конца своей жизни . Это определенно мертвый. PHP 5.4 будет поддерживаться на весь 2015 год, то есть, на тот момент, когда я пишу, еще один год.
Тем не менее, WordPress по-прежнему поддерживает PHP 5.2, но никто не должен писать ни одной строки кода, поддерживающей эту версию, особенно если код является ООП.
Есть разные причины:
Если вы не хотите использовать код PHP 5.4+, используйте как минимум 5.3+
пример
На данный момент пришло время рассмотреть более старые ответы, основанные на том, что я сказал до здесь.
Если нам больше не нужно заботиться о 5.2, мы можем и должны использовать пространства имен.
Для лучшего объяснения принципа единой ответственности в моем примере будут использоваться 3 класса: один, который делает что-то на внешнем интерфейсе, один на внутреннем и третий, используемый в обоих случаях.
Админ класс:
Фронтенд класс:
Интерфейс инструментов:
И класс Tools, используемый двумя другими:
Имея эти классы, я могу создавать их экземпляры, используя правильные хуки. Что-то вроде:
Инверсия зависимости и инъекция зависимости
В приведенном выше примере я использовал пространства имен и анонимные функции для создания экземпляров разных классов с разными хуками, применяя на практике то, что я сказал выше.
Обратите внимание, как пространства имен позволяют создавать классы с именами без префиксов.
Я применил другую концепцию, которая была косвенно упомянута выше: внедрение зависимости , это один из методов применения принципа зависимости зависимости , «D» в аббревиатуре SOLID.
Tools
Класс «впрыскивается» в двух других классах , когда они инстанцируется, так что в этом случае можно разделить ответственность.Кроме того,
AdminStuff
иFrontStuff
классы используют подсказки типов, чтобы объявить, что им нужен класс, который реализуетToolsInterface
.Таким образом, мы или пользователи, которые используют наш код, могут использовать разные реализации одного и того же интерфейса, что делает наш код не связанным с конкретным классом, а с абстракцией: это именно то, о чем говорит принцип инверсии зависимости.
Однако приведенный выше пример может быть дополнительно улучшен. Посмотрим как.
автопогрузчик
Хороший способ написать более читаемый код ООП - это не смешивать определения типов (интерфейсы, классы) с другим кодом, а помещать каждый тип в отдельный файл.
Это правило также является одним из стандартов кодирования PSR-1 1 .
Тем не менее, перед тем, как использовать класс, нужно запросить файл, который его содержит.
Это может быть ошеломляющим, но PHP предоставляет служебные функции для автоматической загрузки класса, когда это требуется, используя обратный вызов, который загружает файл на основе его имени.
Использование пространств имен становится очень простым, потому что теперь можно сопоставить структуру папок со структурой пространства имен.
Это не только возможно, но и является еще одним стандартом PSR (или лучше 2: PSR-0 теперь не рекомендуется, а PSR-4 ).
Следуя этим стандартам, можно использовать различные инструменты, которые обрабатывают автозагрузку, без необходимости кодировать собственный автозагрузчик.
Я должен сказать, что стандарты кодирования WordPress имеют разные правила именования файлов.
Поэтому при написании кода для ядра WordPress разработчики должны следовать правилам WP, но при написании пользовательского кода это выбор разработчика, но использование стандарта PSR проще в использовании уже написанных инструментов 2 .
Шаблоны глобального доступа, реестра и поиска сервисов.
Одна из самых больших проблем при создании экземпляров классов плагинов в WordPress - как получить к ним доступ из различных частей кода.
Сам WordPress использует глобальный подход: переменные сохраняются в глобальной области видимости, делая их доступными везде. Каждый разработчик WP набирает слово
global
тысячи раз в своей карьере.Это также подход, который я использовал в приведенном выше примере, но это зло .
Этот ответ уже слишком длинный, чтобы я мог объяснить, почему, но чтение первых результатов в поисковой выдаче для «глобальных переменных зла» является хорошей отправной точкой.
Но как можно избежать глобальных переменных?
Есть разные способы.
Некоторые из старых ответов здесь используют подход статического экземпляра .
Это просто и довольно хорошо, но это требует реализации шаблона для каждого класса, к которому мы хотим получить доступ.
Более того, во многих случаях этот подход позволяет решить проблему классов бога, поскольку разработчики делают доступным основной класс с помощью этого метода, а затем используют его для доступа ко всем другим классам.
Я уже объяснил, насколько плох класс богов, поэтому подход статического экземпляра - это хороший способ, когда плагин должен сделать доступным только один или два класса.
Это не означает, что его можно использовать только для плагинов, имеющих всего пару классов. Фактически, при правильном использовании принципа внедрения зависимостей можно создавать довольно сложные приложения без необходимости делать глобально доступным большое количество объектов.
Однако иногда плагинам необходимо сделать доступными некоторые классы, и в этом случае подход статического экземпляра является подавляющим.
Другой возможный подход заключается в использовании шаблона реестра .
Это очень простая реализация:
Используя этот класс, можно хранить объекты в объекте реестра по идентификатору, поэтому, имея доступ к реестру, можно получить доступ ко всем объектам. Конечно, когда объект создается впервые, его необходимо добавить в реестр.
Пример:
Приведенный выше пример ясно показывает, что для того, чтобы реестр был полезным, он должен быть общедоступным. Глобальная переменная для единственного реестра не так уж плоха, однако для неглобальных пуристов можно реализовать подход статического экземпляра для реестра или, возможно, функцию со статической переменной:
При первом вызове функции она создает экземпляр реестра, а при последующих вызовах просто возвращает его.
Еще один специфичный для WordPress метод, делающий класс глобально доступным, - это возвращение экземпляра объекта из фильтра. Что-то вроде этого:
После этого везде нужен реестр:
Другим шаблоном, который можно использовать, является шаблон локатора службы . Это похоже на шаблон реестра, но локаторы служб передаются различным классам с помощью внедрения зависимостей.
Основная проблема с этим шаблоном состоит в том, что он скрывает зависимости классов, затрудняя поддержку и чтение кода.
DI Контейнеры
Независимо от метода, используемого для обеспечения глобального доступа к реестру или локатору службы, объекты должны храниться там, а перед тем, как они будут сохранены, их необходимо создать.
В сложных приложениях, где существует довольно много классов, и многие из них имеют несколько зависимостей, создание экземпляров классов требует большого количества кода, поэтому вероятность ошибок возрастает: несуществующий код не может иметь ошибок.
В последние годы появилось несколько библиотек PHP, которые помогают разработчикам PHP легко создавать экземпляры и хранить экземпляры объектов, автоматически разрешая их зависимости.
Эти библиотеки известны как контейнеры внедрения зависимостей, потому что они способны создавать экземпляры классов, разрешающих зависимости, а также хранить объекты и возвращать их при необходимости, действуя аналогично объекту реестра.
Обычно при использовании DI-контейнеров разработчикам приходится устанавливать зависимости для каждого класса приложения, и затем в первый раз, когда в коде необходим класс, он создается с надлежащими зависимостями, и один и тот же экземпляр возвращается снова и снова при последующих запросах. ,
Некоторые DI-контейнеры также способны автоматически обнаруживать зависимости без конфигурации, но с использованием PHP-отражения .
Некоторые хорошо известные контейнеры DI:
и много других.
Я хочу отметить, что для простых плагинов, которые включают в себя только несколько классов, а классы имеют мало зависимостей, вероятно, не стоит использовать контейнеры DI: метод статического экземпляра или глобальный доступный реестр - хорошие решения, но для сложных плагинов преимущество контейнера DI становится очевидным.
Конечно, даже объекты-контейнеры DI должны быть доступны для использования в приложении, и для этого можно использовать один из методов, описанных выше, глобальную переменную, статическую переменную экземпляра, возвращение объекта через фильтр и так далее.
Композитор
Использовать DI-контейнер часто означает использование стороннего кода. В настоящее время в PHP, когда нам нужно использовать внешнюю библиотеку (то есть не только DI-контейнеры, но и любой код, который не является частью приложения), просто загрузить его и поместить в папку нашего приложения не считается хорошей практикой. Даже если мы являемся авторами этого другого куска кода.
Отделение кода приложения от внешних зависимостей является признаком лучшей организации, лучшей надежности и лучшей работоспособности кода.
Composer , является де-факто стандартом в сообществе PHP для управления зависимостями PHP. Это далеко не только мейнстрим в WP сообществе, но и инструмент, который должен знать каждый разработчик PHP и WordPress, если не использовать.
Этот ответ уже размером с книгу, чтобы можно было продолжить обсуждение, а также обсуждение Composer здесь, вероятно, не по теме, его упоминали только для полноты картины.
Для получения дополнительной информации посетите сайт Composer, а также стоит прочитать этот мини-сайт, созданный @Rarst .
1 PSR - это стандарты стандартов PHP, выпущенные PHP Framework Interop Group
2 Composer (библиотека, которая будет упомянута в этом ответе) среди прочего также содержит утилиту автозагрузки.
источник
Я использую следующую структуру:
Примечания:
init
метод)Отказ от ответственности Я еще не использую модульные тесты ( так много вещей на myplate ) и слышу, что статический может быть менее предпочтительным для них. Сделайте свое исследование по этому вопросу, если вам нужно проверить его.
источник
Все зависит от функциональности.
Однажды я создал плагин, который регистрировал скрипты, когда вызывался конструктор, поэтому мне пришлось его
wp_enqueue_scripts
зацепить.Если вы хотите вызвать его, когда ваш
functions.php
файл загружен, вы можете создать экземпляр самостоятельно,$class_instance = new ClassName();
как вы упомянули.Вы можете рассмотреть скорость и использование памяти. Я ничего об этом не знаю, но могу представить, что в некоторых случаях есть неназванные хуки. Создав свой экземпляр на этом хуке, вы можете сэкономить некоторые ресурсы сервера.
источник
init()
метод, чтобы экземпляр класса вызывался в области видимости класса, а не в другой области видимости, где вы могли бы перезаписать существующие переменные.Я знаю, что это пара лет, но в то же время php 5.3 поддерживает анонимные методы , поэтому я придумал это:
и почему-то мне это нравится больше всего. Я могу использовать обычные конструкторы, и мне не нужно определять какие-либо методы "init" или "on_load", которые портят мои структуры ООП.
источник