Плагин WordPress: как избежать «тесной связи»?

33

Я работаю над плагином WordPress и пытаюсь обеспечить лучшие практики. У меня есть два класса, мой класс плагина "Jargonaut", который требуется, а затем еще один класс под названием "Словарь", который включен в require_once() в мой основной файл плагина.

Большая часть кода в классе Jargonaut указывает на инициализацию и предоставляет функции, подобные контроллеру, но большая часть из них сильно зависит от использования объекта Dictionary (т.е. тесно связана с моим пониманием термина). Я хочу, чтобы класс Dictionary был разделен, поскольку он больше похож на модель (в архитектуре MVC) и взаимодействует с моей базой данных.

Я вижу много серой области в жесткой и свободной связи, и мне трудно решить, сколько слишком много?

  • 9
    Можете ли вы сделать вопрос более точным? Завершение утверждения с вопросительным знаком не делает его вопросом?
  • 2
    Вероятно, это следует перенести в WPSE.
Теги:
oop

1 ответ

59
Лучший ответ

Если вашему плагину нужен объект словаря, он должен запросить его:

class MyPlugin
{
    /**
     * @var Dictionary
     */
    private $dictionary;
    private function __construct(Dictionary $dictionary)
    {
        $this->dictionary = $dictionary;
    }

Теперь вы свободно связали свой плагин с Dictionary, класс плагинов больше не отвечает за создание Словаря для себя, потому что он был введен. Он принимает то, что ему нужно.

Итак, как это будет работать? Плагин должен быть создан где-то, поэтому для этого нужен factory. Метод сборки factory знает, что нужно вашему плагину:

class MyPluginFactory
{
    public static function build($pluginName)
    {
        $plugin = NULL;
        switch($pluginName)
        {
            case 'MyPlugin':
                $dictionary = new Dictionary();
                $plugin = new MyPlugin($dictionary);
        }
        return $plugin;
    }
}

Поскольку это wordpress, мы знаем, что начальная загрузка плагина выполняется путем включения файла плагина. Поэтому при его запуске необходимо создать плагин. Поскольку вложения выполняются в глобальном масштабе, мы хотим сохранить объект плагина в памяти, но, возможно, недоступны как глобальная переменная. Это не мешает вам создавать несколько экземпляров плагина, но это гарантирует, что когда wordpress инициализирует ваш плагин (загружает ваш плагин), он будет использовать только один экземпляр. Это можно сделать, добавив плагин factory к некоторой дополнительной функции:

class MyPluginFactory
{
    ...
    public static $plugins;
    public static function bootstrap($pluginName)
    {
        $plugin  = self::build($pluginName);
        self::$plugins[] = $plugin;
        return $plugin;
    }

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

Это в основном отделяет ваш код плагина от самого Wordpress. Вы также можете создать класс, который предлагает и взаимодействует с любой функцией Wordpress, которую вы используете, поэтому вы не привязаны к этим функциям напрямую, и ваш код плагина остается чистым и слабо связан с самим wordpress.

class WordpressSystem
{
    public function registerFilter($name, $plugin, $methodName)
    {
        ... do what this needs with WP, e.g. call the global wordpress function to register a filter.
    }
    ...
}

Затем добавьте его как зависимость снова, если вашему плагину нужен WordpressSystem для выполнения задач (что обычно имеет место):

class MyPlugin
{
    ...
    public function __construct(WordpressSystem $wp, Dictionary $dictionary)
    ...

Итак, чтобы окончательно завершить это, нужен только файл php-плагина:

<?php
/*
 * MyPlugin
 * 
 * Copyright 2010 by hakre <hakre.wordpress.com>, some rights reserved.
 *
 * Wordpress Plugin Header:
 * 
 *   Plugin Name:    My Plugin
 *   Plugin URI:     http://hakre.wordpress.com/plugins/my-plugin/
 *   Description:    Yet another wordpress plugin, but this time mine
 *   Version:        1.2-beta-2
 *   Stable tag:     1.1
 *   Min WP Version: 2.9
 *   Author:         hakre
 *   Author URI:     http://hakre.wordpress.com/
 *   Donate link:    http://www.prisonradio.org/donate.htm
 *   Tags:           my
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
Namespace MyPlugin;

# if your file is named 'MyPlugin.php' this will be 'MyPlugin'.
return PluginFactory::bootstrap(basename($plugin, '.php'));

class PluginFactory
{
    private static $plugins;
    public static function bootstrap($pluginName)
    {
        $plugin = self::build($pluginName);
        self::$plugins[] = $plugin;
        return $plugin;
    }
    public static function build($pluginName)
    {
        $plugin = NULL;
        switch($pluginName)
        {
            case 'MyPlugin':
                # Make your plugin work with different Wordpress Implementations.
                $system = new System\Wordpress3();
                $dictionary = new Dictionary();
                $plugin = new Plugin($system, $dictionary);
        }
        return $plugin;
    }
}

class Plugin
{
    /**
     * @var System
     */
    private $system;
    /**
     * @var Dictionary
     */
    private $dictionary;
    private function __construct(System $system, Dictionary $dictionary)
    {
        $this->system = $system;
        $this->dictionary = $dictionary;
    }

...

Метод bootstrap также может позаботиться о регистрации автозагрузчика или выполнить запрос.

Надеюсь, это полезно.

  • 0
    @hakre - пытаясь следовать вашему примеру, похоже, что $this->build($pluginName) должен был быть self::build($pluginName) поскольку он находится в статической функции, верно? (Я сделал правку, которая должна быть рассмотрена в первую очередь.) Но меня смущает ваше заявление return, которое возвращает MyPluginFactory::bootstrap() ; Я не понимаю, что вы пытаетесь вызвать, и я не осознавал, что вы можете вызвать файл .PHP как функцию; как это возможно? Или вы просто показывали псевдокод?
  • 0
    @hakre - Исследуя больше (я еще не начал использовать пространства имен) , похоже, что ваш вызов MyPluginFactory::bootstrap() действительно должен быть \MyPlugin\Factory::bootstrap() , верно? Тем не менее, не уверен, как работает возврат значения из файла .PHP ...
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню