35 Stimmen

WordPress-Plugin: Wie vermeide ich "enge Kopplung"?

Ich arbeite an einem WordPress-Plugin und versuche, die besten Praktiken sicherzustellen. Ich habe zwei Klassen, meine Plugin-Klasse "Jargonaut", die erforderlich ist, und dann eine weitere Klasse namens "Dictionary", die mit enthalten ist require_once() in meine Haupt-Plugin-Datei.

Der größte Teil des Codes in der Jargonaut-Klasse befasst sich mit der Initialisierung und bietet Controller-ähnliche Funktionen, aber ein Großteil davon ist in hohem Maße von der Verwendung des Dictionary-Objekts abhängig (d. h. nach meinem Verständnis des Begriffs "eng gekoppelt"). Ich möchte die Dictionary-Klasse getrennt halten, da sie sich eher wie ein Modell (in der MVC-Architektur) verhält und über Schnittstellen mit meiner Datenbank verbunden ist.

Ich sehe eine große Grauzone zwischen fester und loser Kopplung und es fällt mir schwer zu entscheiden, wie viel zu viel ist.

60voto

hakre Punkte 184133

Wenn Ihr Plugin das Wörterbuchobjekt benötigt, muss es danach fragen:

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

Sie haben Ihr Plugin nun lose mit der Dictionary ist die Plugin-Klasse nicht mehr dafür verantwortlich, das Dictionary für sich selbst zu erstellen, da es injiziert wird. Sie nimmt sich, was sie braucht.

Und wie soll das funktionieren? Das Plugin muss irgendwo erstellt werden, also braucht es eine Fabrik. Die Build-Methode der Fabrik weiß, was Ihr Plugin braucht:

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

Da es sich hier um WordPress handelt, wissen wir, dass das Bootstrapping des Plugins durch Einbindung der Plugin-Datei erfolgt. Zu Beginn muss also das Plugin erstellt werden. Da Includes im globalen Bereich durchgeführt werden, wollen wir das Plugin-Objekt im Speicher behalten, ohne dass es als globale Variable verfügbar ist. Dies hindert Sie nicht daran, mehr als eine Plugin-Instanz zu erstellen, aber es stellt sicher, dass Wordpress bei der Initialisierung Ihres Plugins (beim Laden Ihres Plugins) nur diese eine Instanz verwendet. Dies kann erreicht werden, indem die Plugin-Factory eine zusätzliche Funktion erhält:

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

Achten Sie hier darauf, dass die einzige Verwendung der statischen Klassenvariable darin besteht, sicherzustellen, dass das Plugin im Speicher bleibt. Technisch gesehen handelt es sich um eine globale Variable, die wir normalerweise verhindern wollen, aber die Instanz muss irgendwo gespeichert werden, also ist sie hier (ich habe sie in public geändert, weil sie ist eine globale Variable, und es sollte sich nicht scheuen, sie zu verwenden. Eine öffentliche Variable kann unter bestimmten Umständen helfen, wenn private oder protected zu restriktiv sind. Außerdem sollte es kein Problem sein. Wenn es ist ein Problem, gibt es ein anderes Problem, das zuerst behoben werden sollte).

Dies entkoppelt im Grunde Ihren Plugin-Code von Wordpress selbst. Vielleicht möchten Sie auch eine Klasse erstellen, die eine Schnittstelle zu jeder Wordpress-Funktion bietet, die Sie verwenden, damit Sie nicht direkt an diese Funktionen gebunden sind und Ihr Plugin-Code sauber und lose an Wordpress selbst gekoppelt bleibt.

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.
    }
    ...
}

Fügen Sie es dann wieder als Abhängigkeit hinzu, wenn Ihr Plugin die WordpressSystem um Aufgaben zu erfüllen (was normalerweise der Fall ist):

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

Um das Ganze abzuschließen, wird nur noch die php-Datei des Plugins benötigt:

<?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;
    }

...

Die Bootstrap-Methode kann sich auch um die Registrierung eines Autoloaders kümmern oder die erforderlichen Aufgaben übernehmen.

Ich hoffe, dies ist nützlich.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X