Архитектура плагина php

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

Идея состоит в том, что каждый класс расширяет своего рода наблюдатель, как класс. Таким образом, класс Template, BaseController и т. Д. Всегда расширяют класс Plugin.

class BaseController extends Plugin { public function __construct() { // Plugin check, notify all loaded plugins $this->checkForEarlyHooks(); // Init some standard stuff $this->view = new Template(); $this->baseLayout = 'layout.html'; $this->something = new Something(); // Plugin check, notify all loaded plugins $this->checkForLateHooks(); } } 

Итак, что в основном происходит здесь, так это то, что когда indexController расширяет baseController, выполняется проверка плагина. В этом случае для конструктора. Это может быть удобно, если вы хотите сделать какую-то проверку входа в систему с помощью плагина, прежде чем на самом деле вызывается метод Action.

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

Также обратите внимание, что он проверяет загруженный список плагинов 2 раза. Прежде чем что-либо загрузится (раньше) в конструкторе, и когда все вары будут загружены (позже).

Я также могу добавить переменные в функцию checkForLateHooks (). Таким образом, функции hook также могут манипулировать ими, как и переменная baseLayout.

Функция hook будет выглядеть так:

 public function hookConstruct ( &$baseLayout ) { $baseLayout = 'login.html'; } 

Теперь, в основном, мой вопрос: этот подход какой-то хороший? Я знаю, что, возможно, есть много других способов сделать это. Но я в основном не хочу сталкиваться с проблемами дизайна позже. Сейчас это кажется хорошей идеей, но вы никогда не знаете, как все будет развиваться позже …

Если я помню это правильно (со всех сообщений, которые я прочитал), это похоже на WordPress (и некоторые другие фреймворки).

UPDATE : ответ теперь отражает современные ссылки и лучшее описание.

Конечно, существует много разных способов разработки плагиновой системы и, возможно, задание https://softwareengineering.stackexchange.com/ даст вам больше идей, но я постараюсь помочь, делясь своими идеями и опытом.

Я расскажу о некоторых своих собственных опытах, которые я узнал из серии своих собственных фреймворков. В настоящее время Agile UI и Agile Data поддерживают многие функции, которые будут расширены, но я сосредоточусь на «Компонентах»,

КРЮКИ

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

Во время рефакторинга моих фреймворков я разделил реализацию перехвата на отдельный признак и задокументировал его здесь: http://agile-core.readthedocs.io/en/develop/hook.html

Хост-приложение:

 ... some code here .. $this->hook('beforeInit'); $this->init(); $this->hook('afterInit'); ... code goes on .. 

Плагин:

 $host_app->addHook('beforeInit', function($object) { echo "About to execute init of $object"; }); 

Компоненты пользовательского интерфейса

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

Компонент – это объект, который может быть связан с макетом или другим компонентом. Каждый компонент способен передавать и передавать дополнительный HTML / JS своему родительскому элементу. Большинство компонентов также будут являться объектами-преломлениями.

Этот подход называется «Render Tree», а выполнение приложения проходит через 2 этапа – «инициализация дерева рендеринга», а затем «рендеринг».

Хост-приложение:

 $layout->menu = new \atk4\ui\Menu(); $layout->add($layout->menu, 'TopMenu'); 

Вышеприведенный код показывает, как новый компонент (меню) можно инициализировать и вставить в $layou . Кроме того, вывод HTML из меню $ направляется в тег {$ TopMenu}, который определен в шаблоне HTML макета.

Плагин может взаимодействовать с деревом рендеринга:

  • добавление большего количества компонентов в дерево
  • влияя на существующие компоненты (например, добавить новый пункт меню)
  • уничтожение любого из существующих компонентов

Когда эти подходы объединены, вы можете использовать что-то вроде этого:

 $app->addHook('afterInitLayout', function($app) { $app->layout->menu->destroy(); // remove default menu $app->layout->menu = new \plugin\SuperMenu(); $app->layout->add($app->layout->menu); }); 

Это можно использовать для замены стандартного меню с более мощной реализацией из вашего дополнения.

Моя реализация компонентов документирована здесь:

http://agile-ui.readthedocs.io/en/latest/view.html#initializing-render-tree

ОТДЕЛЕНИЕ UI / DATA

Хотя, возможно, не так много ответов на вопрос, но еще один мощный способ расширения – это разделение проблем. Все компоненты пользовательского интерфейса в пользовательском интерфейсе Agile не знают, как делать что-либо с данными.

Хотя многие генераторы UI требуют, чтобы разработчик вручную создавал их и связывался с данными, я вводил объект «Model» следующим образом:

 $form->setModel(new User($db)); // populates name, surname and gender fields 

Демо: http://ui.agiletoolkit.org/demos/form2.php (2-я форма)

В этом подходе объект User содержит достаточно метаданных для заполнения Формой своих полей, титры выполняют валидацию, а также сохраняют / загружают данные.

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

ДРУГИЕ ПОДХОДЫ

Некоторые другие подходы к расширению с дополнениями включают в себя:

Фабрика:

Возможность разрешить класс, указанный в виде строки в пространстве имен / файле:

 $api->add('MyClass'); 

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

Новые типы / Черты:

Add-on может предоставить новые классы, добавляющие Persistences, Table Columns, Form Fields, Actions и т. Д.

ВЫВОД

Я думаю, что добавление deign сводится к:

  • простота установки и использования
  • нужна ли надстройка для работы в готовом виде?
  • избегать конфликтов между надстройками
  • определение различных типов дополнений – аутентификация, пользовательский интерфейс, поведение
  • может дополнять расширение другого дополнения
  • будет дополнять дизайн приложения, данные и архитектура?
  • дают много возможностей для дополнений, не жертвуя производительностью

Взгляните на PHPPlugin на https://github.com/gheevel/PHPPlugin . Простая инфраструктура плагинов PHP, вдохновленная архитектурой плагинов eclipse и jira. В основном, ваше приложение может определять точки расширения, а экземпляры плагина могут регистрироваться в этих точках расширения для обеспечения дополнительной функциональности. Хорошо работает в сочетании с композитором и / или symfony.