Beste Weg, um eine Klasse in einem WP-Plugin zu initiieren?

89

Ich habe ein Plugin erstellt und natürlich wollte ich als ich selbst einen netten OO-Ansatz verfolgen. Ich habe jetzt diese Klasse erstellt und dann direkt darunter eine Instanz dieser Klasse erstellt:

class ClassName {

    public function __construct(){

    }
}

$class_instance = new ClassName();  

Ich gehe davon aus, dass es mehr WP-Möglichkeiten gibt, diese Klasse zu initiieren, und dann bin ich auf Leute gestoßen, die sagten, sie hätten lieber eine init()Funktion als eine __construct(). Und in ähnlicher Weise fand ich die ein paar Leute mit folgenden Haken:

class ClassName {

    public function init(){

    }
}
add_action( 'load-plugins.php', array( 'ClassName', 'init' ) );

Was wird im Allgemeinen als die beste Methode zum Erstellen einer WP-Klasseninstanz beim Laden angesehen und ob diese als global zugreifbare Variable vorliegt?

HINWEIS: Als interessanter Nebeneffekt ist mir aufgefallen, dass register_activation_hook()der Aufruf zwar aus dem __construct, der Aufruf aus init()dem zweiten Beispiel nicht möglich ist. Vielleicht könnte mich jemand in diesem Punkt aufklären.

Edit: Vielen Dank für die Antworten, es gibt natürlich einiges an Debatte darüber, wie die Initialisierung innerhalb der Klasse selbst gehandhabt wird, aber ich denke, es gibt im Allgemeinen einen ziemlich guten Konsens, add_action( 'plugins_loaded', ...);der der beste Weg ist, um es tatsächlich zu starten ...

Bearbeiten: Nur um die Sache zu verwirren, ich habe auch gesehen, dass dies verwendet wird (obwohl ich diese Methode selbst nicht verwenden würde, weil das Umwandeln einer OO-Klasse in eine Funktion den Sinn zu verlieren scheint):

// Start up this plugin
add_action( 'init', 'ClassName' );
function ClassName() {
    global $class_name;
    $class_name = new ClassName();
}
Kalpaitch
quelle
1
In Bezug auf die letzte Bearbeitung, wenn diese in der gleichen Plugin-Datei wie die Klasse enthalten ist, wird sie etwas unbrauchbar. Sie können die Klasse auch gemäß der von mir beschriebenen Methode instanziieren. Auch wenn es in einer separaten Datei ist, ist es immer noch etwas sinnlos. Ich kann nur feststellen, ob Sie eine Wrapper-Funktion erstellen möchten, mit der Sie eine Klasse außerhalb Ihrer Plug-in-Dateien, innerhalb von Themen usw. instanziieren können. Trotzdem müsste ich fragen, welche Logik dahinter steckt, denn die korrekte Verwendung von Bedingungen und Haken sollte eine genaue Kontrolle über die Instanziierung ermöglichen, sodass Sie sich stattdessen auf die Verwendung des Plugins konzentrieren können.
Adam
Ich bin damit einverstanden, aber ich dachte, es lohnt sich, es in ein paar WP-Plugins zu integrieren.
Kalpaitch

Antworten:

60

Gute Frage, es gibt eine Reihe von Ansätzen und es kommt darauf an, was Sie erreichen wollen.

Das tue ich oft;

add_action( 'plugins_loaded', array( 'someClassy', 'init' ));

class someClassy {

    public static function init() {
        $class = __CLASS__;
        new $class;
    }

    public function __construct() {
           //construct what you see fit here...
    }

    //etc...
}

Ein ausführlicheres Beispiel, das sich aus jüngsten Diskussionen zu genau diesem Thema im Chatroom ergab, kann WPSE-Mitglied toscho in dieser Zusammenfassung entnehmen .

Der leere Konstruktoransatz.

Hier finden Sie einen Auszug der Vor- und Nachteile, die sich aus dem obigen Überblick ergeben und den vollständigen Ansatz des leeren Konstruktors veranschaulichen.

  • Vorteile:

    • Unit-Tests können neue Instanzen erstellen, ohne dass automatisch Hooks aktiviert werden. Kein Singleton.

    • Keine globale Variable erforderlich.

    • Wer mit der Plugin-Instanz arbeiten möchte, kann einfach T5_Plugin_Class_Demo :: get_instance () aufrufen.

    • Einfach zu deaktivieren.

    • Immer noch echtes OOP: Keine Arbeitsmethode ist statisch.

  • Nachteil:

    • Vielleicht schwerer zu lesen?

Der Nachteil ist meiner Meinung nach ein schwacher, weshalb es mein bevorzugter Ansatz sein müsste, aber nicht der einzige, den ich benutze. Tatsächlich werden ohne Zweifel einige andere Schwergewichte in Kürze zu diesem Thema Stellung nehmen, da es einige gute Meinungen zu diesem Thema gibt, die geäußert werden sollten.


Hinweis: Ich muss das wichtigste Beispiel von toscho finden , das 3 oder 4 Vergleiche zum Instanziieren einer Klasse in einem Plugin durchlief, in dem die Vor- und Nachteile der einzelnen Plugins untersucht wurden Die anderen Beispiele bieten einen guten Kontrast zu diesem Thema. Hoffentlich hat toscho das noch in der Akte.

Hinweis: Die WPSE-Antwort zu diesem Thema mit relevanten Beispielen und Vergleichen. Auch die beste Lösung zum Beispiel eine Klasse in WordPress.

add_shortcode( 'baztag', array( My_Plugin::get_instance(), 'foo' ) );
class My_Plugin {

    private $var = 'foo';

    protected static $instance = NULL;

    public static function get_instance() {

        // create an object
        NULL === self::$instance and self::$instance = new self;

        return self::$instance; // return the object
    }

    public function foo() {

        return $this->var; // never echo or print in a shortcode!
    }
}
Adam
quelle
Was wäre der Unterschied zwischen add_action ('plugins_loaded', ...); und add_action ('load-plugins.php', ...); Das Beispiel, das ich genommen habe, verwendete das letztere
Kalpaitch
1
Nach meinem Verständnis ist load-plugins.php, obwohl es funktioniert, mit der Kerndatei verknüpft update.phpund gehört nicht zu den üblichen Standardaktionen, auf die man sich verlassen sollte, wenn es um die Reihenfolge von Ereignissen geht, die während der Initialisierung ausgelöst werden, und aus diesem Grund bevorzuge ich um die Haken zu verwenden, die in diesem Fall zutreffen plugins_loaded. Dies ist, was ich oft als eine schnelle Momentaufnahme von dem bezeichne, was bei der Aktionsreferenz passiert . Meine Erklärung ist nicht vollständig.
Adam
4
Ich mag diesen singletonartigen Ansatz. Ich frage Sie jedoch, ob Sie plugins_loaded als Initialisierungsaktions-Hook verwenden möchten. Dieser Hook soll ausgeführt werden, nachdem alle Plugins geladen wurden. Wenn Sie sich danach einhängen, hijacken Sie diesen Hook und können sich an Konflikten oder Problemen mit der Startreihenfolge mit anderen Plugins oder Themes erfreuen, die sich in plugins_loaded einhängen. Ich würde mich an keiner Aktion beteiligen, um Ihre Initialisierungsmethode auszuführen. Die Plugin-Architektur wurde so konzipiert, dass sie inline und nicht für eine Aktion ausgeführt wird.
Tom Auger
2
Beachten Sie, dass Sie bei Verwendung register_activation_hook()diese Funktion aufrufen müssen, bevor die plugins_loadedAktion ausgelöst wird.
Geert
1
Als zusätzliche Information siehe diesen Beitrag von @mikeschinkel und den Kommentar in den Kommentaren. hardcorewp.com/2012/…
Bueltge
78

Genau zwei Jahre nachdem die ursprüngliche Frage gestellt wurde, möchte ich Sie auf einige Dinge hinweisen. (Bitten Sie mich nicht , jemals auf eine Menge Dinge hinzuweisen ).

Richtiger Haken

Um eine Plugin-Klasse zu instanziieren, sollte der richtige Hook verwendet werden. Es gibt keine allgemeine Regel, für die es gilt, weil es davon abhängt, was die Klasse tut.

Die Verwendung eines sehr frühen Hooks macht "plugins_loaded"oft keinen Sinn, da ein solcher Hook für Admin-, Frontend- und AJAX-Anfragen ausgelöst wird, aber sehr oft ist ein späterer Hook weitaus besser, da er die Instanziierung von Plugin-Klassen nur bei Bedarf ermöglicht.

Beispielsweise kann eine Klasse instanziiert werden, die Aufgaben für Vorlagen ausführt "template_redirect".

Im Allgemeinen ist es sehr selten, dass eine Klasse instanziiert werden muss, bevor "wp_loaded"sie ausgelöst wird.

Keine Gottesklasse

Die meisten Klassen, die in älteren Antworten als Beispiele verwendet werden, verwenden eine Klasse mit dem Namen "like" "Prefix_Example_Plugin"oder " "My_Plugin"...". Dies weist darauf hin, dass es wahrscheinlich eine Hauptklasse für das Plugin gibt.

Nun, es sei denn, ein Plugin wird von einer einzelnen Klasse erstellt (in diesem Fall ist es absolut sinnvoll, es nach dem Namen des Plugins zu benennen), um eine Klasse zu erstellen, die das gesamte Plugin verwaltet (z. B. alle Hooks hinzufügen, die ein Plugin benötigt, oder alle anderen Plugin-Klassen instanziieren) ) kann als schlechtes Beispiel für einen Gottesgegenstand angesehen werden .

In der objektorientierten Programmierung sollte Code SOLID sein, wobei "S" für "Prinzip der Einzelverantwortung" steht .

Das bedeutet, dass jede Klasse eine einzige Sache machen sollte. Bei der Entwicklung von WordPress-Plugins sollten Entwickler vermeiden, einen einzelnen Hook zum Instanziieren einer Haupt- Plugin-Klasse zu verwenden. Je nach Klassenverantwortung sollten jedoch unterschiedliche Hooks zum Instanziieren verschiedener Klassen verwendet werden.

Vermeiden Sie Haken im Konstruktor

Dieses Argument wurde in anderen Antworten hier eingeführt, aber ich möchte dieses Konzept erwähnen und diese andere Antwort verknüpfen , wo es im Bereich der Komponententests ziemlich ausführlich erklärt wurde.

Fast 2015: PHP 5.2 ist für Zombies

Seit dem 14. August 2014 hat PHP 5.3 sein Ende erreicht . Es ist definitiv tot. PHP 5.4 wird für das ganze Jahr 2015 unterstützt, dh für ein weiteres Jahr, in dem ich gerade schreibe.

WordPress unterstützt zwar immer noch PHP 5.2, aber niemand sollte eine einzige Codezeile schreiben, die diese Version unterstützt, insbesondere wenn der Code OOP ist.

Es gibt verschiedene Gründe:

  • PHP 5.2 ist vor langer Zeit tot. Es wurden keine Sicherheitsupdates veröffentlicht, das heißt, es ist nicht sicher
  • PHP 5.3 fügte PHP viele Funktionen, anonyme Funktionen und Namespaces über alles hinzu
  • Neuere Versionen von PHP sind viel schneller . PHP ist kostenlos. Die Aktualisierung ist kostenlos. Warum eine langsamere, unsichere Version verwenden, wenn Sie eine schnellere, sicherere kostenlos verwenden können?

Wenn Sie keinen PHP 5.4+ Code verwenden möchten, verwenden Sie mindestens 5.3+

Beispiel

An dieser Stelle ist es an der Zeit, ältere Antworten auf der Grundlage meiner bisherigen Ausführungen zu überprüfen.

Sobald wir uns nicht mehr um 5.2 kümmern müssen, können und sollten wir Namespaces verwenden.

Um das Prinzip der einzelnen Verantwortung besser zu erläutern, werden in meinem Beispiel drei Klassen verwendet, eine, die etwas im Frontend ausführt, eine im Backend und eine dritte, die in beiden Fällen verwendet wird.

Admin-Klasse:

namespace GM\WPSE\Example;

class AdminStuff {

   private $tools;

   function __construct( ToolsInterface $tools ) {
     $this->tools = $tools;
   }

   function setup() {
      // setup class, maybe add hooks
   }

}

Frontend-Klasse:

namespace GM\WPSE\Example;

class FrontStuff {

   private $tools;

   function __construct( ToolsInterface $tools ) {
     $this->tools = $tools;
   }

   function setup() {
      // setup class, maybe add hooks
   }

}

Tools-Schnittstelle:

namespace GM\WPSE\Example;

interface ToolsInterface {

   function doSomething();

}

Und eine Tools-Klasse, die von den anderen beiden verwendet wird:

namespace GM\WPSE\Example;

class Tools implements ToolsInterface {

   function doSomething() {
      return 'done';
   }

}

Mit diesen Klassen kann ich sie mit geeigneten Hooks instanziieren. So etwas wie:

require_once plugin_dir_path( __FILE__ ) . 'src/ToolsInterface.php';
require_once plugin_dir_path( __FILE__ ) . 'src/Tools.php';

add_action( 'admin_init', function() {

   require_once plugin_dir_path( __FILE__ ) . 'src/AdminStuff.php';
   $tools = new GM\WPSE\Example\Tools;
   global $admin_stuff; // this is not ideal, reason is explained below
   $admin_stuff = new GM\WPSE\Example\AdminStuff( $tools ); 
} );

add_action( 'template_redirect', function() {

   require_once plugin_dir_path( __FILE__ ) . 'src/FrontStuff.php';
   $tools = new GM\WPSE\Example\Tools;
   global $front_stuff; // this is not ideal, reason is explained below
   $front_stuff = new GM\WPSE\Example\FrontStuff( $tools );    
} );

Abhängigkeitsinversion & Abhängigkeitsinjektion

Im obigen Beispiel habe ich Namespaces und anonyme Funktionen verwendet, um verschiedene Klassen an verschiedenen Hooks zu instanziieren und das, was ich oben gesagt habe, in die Praxis umzusetzen.

Beachten Sie, wie mit Namespaces Klassen ohne Präfix erstellt werden können.

Ich habe ein anderes Konzept angewendet, das indirekt oben erwähnt wurde: Dependency Injection. Hierbei handelt es sich um eine Methode zur Anwendung des Dependency Inversion Principle , das "D" in der Abkürzung SOLID.

Die ToolsKlasse wird in die beiden anderen Klassen "injiziert", wenn sie instanziiert werden. Auf diese Weise ist es möglich, die Verantwortung zu trennen.

Außerdem verwenden AdminStuffund FrontStuffKlassen Typhinweise, um zu deklarieren, dass sie eine Klasse benötigen, die implementiert wird ToolsInterface.

Auf diese Weise können wir selbst oder Benutzer, die unseren Code verwenden, unterschiedliche Implementierungen derselben Schnittstelle verwenden, sodass unser Code nicht an eine konkrete Klasse, sondern an eine Abstraktion gekoppelt ist: Genau darum geht es beim Prinzip der Abhängigkeitsinversion.

Das obige Beispiel kann jedoch weiter verbessert werden. Mal sehen wie.

Autoloader

Eine gute Möglichkeit, besser lesbaren OOP-Code zu schreiben, besteht darin , die Definition von Typen (Schnittstellen, Klassen) nicht mit anderem Code zu mischen und jeden Typ in einer eigenen Datei abzulegen.

Diese Regel ist auch einer der PSR-1-Codierungsstandards 1 .

Bevor man jedoch eine Klasse verwenden kann, muss man die Datei benötigen, die sie enthält.

Dies kann überwältigend sein, aber PHP bietet Dienstprogrammfunktionen zum automatischen Laden einer Klasse, wenn dies erforderlich ist. Dabei wird ein Rückruf verwendet, der eine Datei basierend auf ihrem Namen lädt.

Die Verwendung von Namespaces wird sehr einfach, da es jetzt möglich ist, die Ordnerstruktur mit der Namespace-Struktur abzugleichen.

Dies ist nicht nur möglich, sondern auch ein anderer PSR-Standard (oder besser 2: PSR-0 jetzt veraltet und PSR-4 ).

Nach diesen Standards ist es möglich, verschiedene Tools für das automatische Laden zu verwenden, ohne einen benutzerdefinierten Autoloader codieren zu müssen.

Ich muss sagen, dass WordPress-Codierungsstandards unterschiedliche Regeln für die Benennung von Dateien haben.

Wenn Entwickler Code für WordPress Core schreiben, müssen sie die WP-Regeln befolgen, aber wenn sie benutzerdefinierten Code schreiben, ist dies eine Entscheidung der Entwickler. Die Verwendung des PSR-Standards ist jedoch einfacher, wenn sie bereits geschriebene Tools 2 verwenden .

Muster für globalen Zugriff, Registrierung und Service Locator.

Eines der größten Probleme beim Instanziieren von Plugin-Klassen in WordPress ist der Zugriff von verschiedenen Teilen des Codes aus.

WordPress selbst verwendet den globalen Ansatz: Variablen werden im globalen Bereich gespeichert und sind somit überall verfügbar. Jeder WP-Entwickler gibt das Wort globalin seiner Karriere tausende Male ein.

Dies ist auch der Ansatz, den ich für das obige Beispiel verwendet habe, aber er ist böse .

Diese Antwort ist bereits viel zu lang, um das Warum näher erläutern zu können, aber das Lesen der ersten Ergebnisse im SERP für "globale Variablen böse" ist ein guter Ausgangspunkt.

Aber wie können globale Variablen vermieden werden?

Es gibt verschiedene Wege.

Einige der älteren Antworten hier verwenden den statischen Instanzansatz .

public static function instance() {

  if ( is_null( self::$instance ) ) {
    self::$instance = new self;
  }

  return self::$instance;
}

Es ist einfach und ziemlich gut, aber es zwingt dazu, das Muster für jede Klasse zu implementieren, auf die wir zugreifen möchten.

Darüber hinaus wird dieser Ansatz häufig zum Problem der God-Klasse, da Entwickler mit dieser Methode eine Hauptklasse zugänglich machen und dann auf alle anderen Klassen zugreifen.

Ich habe bereits erklärt, wie schlecht eine God-Klasse ist, daher ist der Ansatz mit statischen Instanzen ein guter Weg, wenn ein Plugin nur eine oder zwei Klassen zugänglich machen muss.

Dies bedeutet nicht, dass es nur für Plugins mit nur wenigen Klassen verwendet werden kann. Wenn das Prinzip der Abhängigkeitsinjektion richtig angewendet wird, können ziemlich komplexe Anwendungen erstellt werden, ohne dass eine große Anzahl global zugänglich gemacht werden muss von Objekten.

Manchmal müssen Plugins jedoch einige Klassen zugänglich machen , und in diesem Fall ist der Ansatz für statische Instanzen überwältigend.

Ein anderer möglicher Ansatz ist die Verwendung des Registrierungsmusters .

Dies ist eine sehr einfache Implementierung davon:

namespace GM\WPSE\Example;

class Registry {

   private $storage = array();

   function add( $id, $class ) {
     $this->storage[$id] = $class;
   }

   function get( $id ) {
      return array_key_exists( $id, $this->storage ) ? $this->storage[$id] : NULL;
   }

}

Mit dieser Klasse ist es möglich, Objekte über eine ID im Registrierungsobjekt zu speichern. Wenn Sie also Zugriff auf eine Registrierung haben, können Sie auf alle Objekte zugreifen. Wenn ein Objekt zum ersten Mal erstellt wird, muss es natürlich zur Registrierung hinzugefügt werden.

Beispiel:

global $registry;

if ( is_null( $registry->get( 'tools' ) ) ) {
  $tools = new GM\WPSE\Example\Tools;
  $registry->add( 'tools', $tools );
}

if ( is_null( $registry->get( 'front' ) ) ) {
  $front_stuff = new GM\WPSE\Example\FrontStuff( $registry->get( 'tools' ) );    
  $registry->add( 'front', front_stuff );
}

add_action( 'wp', array( $registry->get( 'front' ), 'wp' ) );

Das obige Beispiel verdeutlicht, dass die Registrierung global zugänglich sein muss, um nützlich zu sein. Eine globale Variable für die einzige Registrierung ist nicht sehr schlecht. Für nicht-globale Puristen ist es jedoch möglich, den statischen Instanzansatz für eine Registrierung oder eine Funktion mit einer statischen Variablen zu implementieren:

function gm_wpse_example_registry() {
  static $registry = NULL;
  if ( is_null( $registry ) ) {
    $registry = new GM\WPSE\Example\Registry;
  }
  return $registry;
}

Beim ersten Aufruf der Funktion wird die Registrierung instanziiert, bei nachfolgenden Aufrufen wird sie nur zurückgegeben.

Eine andere WordPress-spezifische Methode, um eine Klasse global zugänglich zu machen, ist die Rückgabe einer Objektinstanz aus einem Filter. Etwas wie das:

$registry = new GM\WPSE\Example\Registry;

add_filter( 'gm_wpse_example_registry', function() use( $registry ) {
  return $registry;
} );

Danach wird überall die Registrierung benötigt:

$registry = apply_filters( 'gm_wpse_example_registry', NULL );

Ein anderes Muster, das verwendet werden kann, ist das Dienstlokalisierungsmuster . Es ähnelt dem Registrierungsmuster, aber Service-Locators werden mithilfe der Abhängigkeitsinjektion an verschiedene Klassen übergeben.

Das Hauptproblem bei diesem Muster besteht darin, dass Klassenabhängigkeiten ausgeblendet werden, was das Verwalten und Lesen von Code erschwert.

DI-Behälter

Unabhängig von der Methode, mit der die Registrierung oder der Service Locator global verfügbar gemacht werden, müssen Objekte dort gespeichert und vor dem Speichern instanziiert werden.

In komplexen Anwendungen, in denen es sehr viele Klassen gibt und viele von ihnen mehrere Abhängigkeiten haben, erfordert das Instanziieren von Klassen viel Code, sodass die Möglichkeit von Fehlern zunimmt: Code, der nicht existiert, kann keine Fehler enthalten.

In den letzten Jahren sind einige PHP-Bibliotheken erschienen, die PHP-Entwicklern helfen, Instanzen von Objekten einfach zu instanziieren und zu speichern und ihre Abhängigkeiten automatisch aufzulösen .

Diese Bibliotheken werden als Dependency Injection Containers bezeichnet, da sie in der Lage sind, Klassen zu instanziieren, die Abhängigkeiten auflösen, sowie Objekte zu speichern und bei Bedarf zurückzugeben, ähnlich wie ein Registrierungsobjekt.

In der Regel müssen Entwickler bei der Verwendung von DI-Containern die Abhängigkeiten für jede Klasse der Anwendung einrichten. Wenn eine Klasse im Code zum ersten Mal benötigt wird, wird sie mit den richtigen Abhängigkeiten instanziiert und dieselbe Instanz wird bei nachfolgenden Anforderungen immer wieder zurückgegeben .

Einige DI-Container sind auch in der Lage, Abhängigkeiten automatisch zu erkennen, ohne sie zu konfigurieren, jedoch mit PHP-Reflektion .

Einige bekannte DI-Container sind:

und viele andere.

Ich möchte darauf hinweisen, dass es für einfache Plugins, die nur wenige Klassen und Klassen betreffen, nicht viele Abhängigkeiten gibt, wahrscheinlich nicht sinnvoll ist, DI-Container zu verwenden: Die statische Instanzmethode oder eine global zugängliche Registrierung sind gute Lösungen, aber für komplexe Plugins Der Vorteil eines DI-Containers wird deutlich.

Selbstverständlich müssen auch DI-Containerobjekte zugänglich sein, um in der Anwendung verwendet werden zu können. Zu diesem Zweck kann eine der oben beschriebenen Methoden verwendet werden: globale Variable, statische Instanzvariable, zurückgegebenes Objekt über Filter usw.

Komponist

Die Verwendung von DI-Containern bedeutet häufig die Verwendung von Drittanbieter-Code. Heute in PHP, wenn wir eine externe lib (also nicht nur DI Container, sondern verwenden müssen , um jeden Code, der nicht Teil der Anwendung ist), einfach herunterladen und es in unserem Anwendungsordner setzen ist keine gute Praxis betrachtet. Auch wenn wir die Autoren dieses anderen Codes sind.

Einen Anwendungscode Entkoppelung von externen Abhängigkeiten ist Zeichen für eine bessere Organisation, bessere Zuverlässigkeit und bessere geistige Gesundheit des Codes.

Composer ist der De-facto- Standard in der PHP-Community zur Verwaltung von PHP-Abhängigkeiten. Weit davon entfernt, auch in der WP-Community Mainstream zu sein , ist es ein Tool, das jeder PHP- und WordPress-Entwickler zumindest kennen sollte, wenn er es nicht nutzt.

Diese Antwort ist bereits buchgroß, um eine weitere Diskussion zu ermöglichen, und die Diskussion über Composer hier ist wahrscheinlich nicht thematisch. Sie wurde nur der Vollständigkeit halber erwähnt.

Weitere Informationen finden Sie auf der Composer-Website. Es lohnt sich auch, diese von @Rarst kuratierte Minisite zu lesen .


1 PSR sind PHP-Standardregeln, die von der PHP Framework Interop Group veröffentlicht wurden

2 Composer (eine Bibliothek, die in dieser Antwort erwähnt wird) enthält unter anderem auch ein Autoloader-Dienstprogramm.

gmazzap
quelle
1
Ein zusätzlicher Hinweis, dass PHP 5.3 auch das Ende des Lebens ist. Ein verantwortungsbewusster Host bietet mindestens 5,4 als Option an, wenn dies nicht der Fall ist
Tom J Nowell
2
"Seit dem 14. August 2014 hat PHP 5.3 sein Ende erreicht. Es ist definitiv tot." Ist die erste Zeile unter "PHP 5.2 ist für Zombies" @TomJNowell
gmazzap
3
Ich frage mich nur, wie würden Sie darauf hinweisen, dass "viele Dinge" aussehen? ;-)
MikeSchinkel
In dem Bestreben, globale Variablen zu vermeiden, gefällt mir die Idee des Registrierungsmusters mit der Funktion und der statischen Variablen. Beim ersten Aufruf der Funktion wird die Registrierung instanziiert, bei nachfolgenden Aufrufen wird sie nur zurückgegeben.
Michael Ecklund
10

Ich benutze folgende Struktur:

Prefix_Example_Plugin::on_load();

/**
 * Example of initial class-based plugin load.
 */
class Prefix_Example_Plugin {

    /**
     * Hooks init (nothing else) and calls things that need to run right away.
     */
    static function on_load() {

        // if needed kill switch goes here (if disable constant defined then return)

        add_action( 'init', array( __CLASS__, 'init' ) );
    }

    /**
     * Further hooks setup, loading files, etc.
     *
     * Note that for hooked methods name equals hook (when possible).
     */
    static function init(  ) {


    }
}

Anmerkungen:

  • hat den Ort für Dinge definiert, die sofort laufen müssen
  • Deaktivieren / Überschreiben für Optimierungen ist einfach (eine initMethode aushängen )
  • Ich glaube nicht, dass ich jemals ein Objekt der Plugin-Klasse verwendet / benötigt habe - es erfordert, dass ich den Überblick behalte, usw .; Dies ist wirklich ein gefälschter Namensraum, nicht OOP (meistens)

Haftungsausschluss Ich verwende noch keine Komponententests ( so viele Dinge auf meinem Schild ) und ich höre, dass statische Aufladung für sie weniger vorzuziehen ist. Recherchieren Sie hierüber, wenn Sie einen Komponententest durchführen müssen.

Rarst
quelle
3
Ich kenne Leute, die viel mit Unit-Tests zu tun haben, die statische / Singleton-Lösungen nicht mögen. Ich denke, wenn Sie vollständig verstehen, was Sie mit statischer Aufladung erreichen wollen, und sich der Konsequenzen dessen zumindest bewusst sind, ist es vollkommen in Ordnung, solche Methoden zu implementieren. Gute Themen rund um dieses Thema bei Stack Overflow
Adam
Das hat mich wirklich zum Nachdenken gebracht. Warum also dann eine Klasse verwenden und nicht einfach auf einfache vorangestellte Funktionen zurückgreifen. Tun wir das nur, um sauberere Funktions- / Methodennamen zu haben? Ich meine, sie mit einem "statischen" b4 verschachteln zu lassen. Ist es so viel besser lesbar? Die Wahrscheinlichkeit eines Namenskonflikts ist in etwa die gleiche wie bei einem einzelnen Klassennamen, wenn Sie korrekte Präfixe verwenden oder wenn ich etwas vermisse?
James Mitch
1
@JamesMitch ja, all-statische Methoden funktionieren meist nur mit gefälschten Namespaces, wie sie in WP verwendet werden. Klassen haben jedoch auch in diesem Fall einige Vorteile gegenüber reinen Funktionen, wie z. B. Autoload und Vererbung. In letzter Zeit bin ich von statischen Methoden zu real instanziierten Objekten übergegangen, die nach Abhängigkeitsinjektionscontainern organisiert sind.
Rarst
3

Alles hängt von der Funktionalität ab.

Ich habe einmal ein Plugin erstellt, das Skripte registriert, als der Konstruktor aufgerufen wurde, also musste ich es am wp_enqueue_scriptsHook einbinden.

Wenn Sie es aufrufen möchten, wenn Ihre functions.phpDatei geladen wird, können Sie genauso gut selbst eine Instanz erstellen, $class_instance = new ClassName();wie Sie es erwähnt haben.

Möglicherweise möchten Sie die Geschwindigkeit und Speichernutzung berücksichtigen. Mir sind keine bekannt, aber ich kann mir vorstellen, dass es in einigen Fällen unangemeldete Haken gibt. Indem Sie Ihre Instanz an diesem Hook erstellen, sparen Sie möglicherweise einige Serverressourcen.

Tim S.
quelle
Cool, danke dafür, ich nehme an, es gibt auch zwei Punkte zu der obigen Frage. Das andere ist, ob __construct geeignet ist oder ob init () eine bessere Möglichkeit ist, die Klasse zu initialisieren.
Kalpaitch
1
Nun, ich würde mich für eine statische init()Methode entscheiden, damit die Klasseninstanz im Geltungsbereich der Klasse aufgerufen wird und nicht in einem anderen Geltungsbereich, in dem Sie möglicherweise vorhandene Variablen überschreiben könnten.
Tim S.
0

Ich weiß , dass dies ein paar Jahre alt ist, aber mittlerweile PHP 5.3 anonyme Methoden unterstützt , so dass ich kam mit dieser:

add_action( 'plugins_loaded', function() { new My_Plugin(); } );

und irgendwie mag ich es am meisten. Ich kann reguläre Konstruktoren verwenden und muss keine "init" - oder "on_load" -Methoden definieren, die meine OOP-Strukturen durcheinander bringen.

Basti
quelle