Tutti i plugin dovrebbero essere incapsulati in una classe?


28

Quando si sviluppa un plug-in, le funzioni devono essere raggruppate in una classe per evitare conflitti nello spazio dei nomi?

L'uso delle classi crea costi generali per le prestazioni di PHP?

Se si verifica un hit delle prestazioni, i nomi delle funzioni dovrebbero essere pre-fissati?


8
Probabilmente più di una domanda PHP di una WordPress, vedi se questa domanda StackOverflow risponde adeguatamente alla tua domanda.
t31os,

Risposte:


24

Quando si sviluppa un plug-in, le funzioni devono essere raggruppate in una classe per evitare conflitti nello spazio dei nomi?

Sì, ma questo è solo uno degli argomenti minori. In realtà questa non è la natura "vera" di una classe in OOAD .

L'uso delle classi crea costi generali per le prestazioni di PHP?

No, in particolare. La cattiva progettazione e / o il cattivo codice scritto o l'ottimizzazione pre-matura creano molti più problemi di prestazioni rispetto alle caratteristiche del linguaggio reale.

Se si verifica un hit delle prestazioni, i nomi delle funzioni dovrebbero essere pre-fissati?

Come scritto, non vi è alcun impatto sulle prestazioni. Il codice scritto errato sarà più un successo prestazionale che un buon codice scritto che ha più righe di codice ma non ti costringe a fare cose cattive.


Linea di fondo:

Puoi utilizzare diversamente le classi per i plugin. Puoi semplicemente usarli per avere una sorta di spazio dei nomi e usarli "solo" per funzioni globali. La forma più diretta di ciò sono le funzioni di classe statica, il seguente esempio di codice mostra sia le prime funzioni globali che le funzioni globali di classe statica:

/* global function */
function myplug_hook()
{
}

add_filter('the_hook', 'myplug_hook');


/* global static function */
class myplug
{
    public static function hook()
    {
    }
}

add_filter('the_hook', 'myplug::hook');

Questo è solo un piccolo esempio che mostra che è necessario digitare di più per il singolo hook. Inoltre mostra come funziona lo spazio dei nomi: è possibile sostituire più facilmente il nome della singola classe per rinominare tutte le funzioni statiche e quindi cercare e sostituire myplug::che potrebbero essere più difficili a myplug_causa di falsi positivi. Ma alla fine non c'è molta differenza.

Il punto chiave è: le funzioni di classe statiche Doc non sono molto altro che funzioni globali Doc .

E anche questo esempio mostra: lo spazio dei nomi va bene, ma con worpdress lo spazio dei nomi si interrompe con l'uso degli hook: la funzione di callback è codificata, quindi il vantaggio nello spazio dei nomi usando la classe (un posto per il nome di base, il nome della classe) non aiuto quando intervieni il tuo codice con wordpress per i nomi hook.

Il vero vantaggio inizia con l'utilizzo di istanze di classe effettive e funzioni non statiche. Ciò ha il vantaggio di poter iniziare a utilizzare i principi OO e di semplificare il codice. Le funzioni di classe statiche sono più un problema che una soluzione.

Quindi è più di un semplice zucchero sintattico.

Il punto chiave è: fare qualcosa che ti aiuti a scrivere il codice che puoi gestire e gestire facilmente. Non sopravvalutare le prestazioni, è un errore comune. Ancora più importante è scrivere codice che sia facile da leggere e da capire, che fa proprio quello di cui hai bisogno. Forse questa domanda e risposta è utile per un'immagine più ampia in questo contesto: Guida Metabox personalizzata multipla .

Un approccio comune che ho anche con plug-in più piccoli è l'utilizzo di una funzione di supporto statico per istanziare il plug-in e il resto risiede all'interno dell'istanza del plug-in. Questo aiuta a incapsulare la logica principale del plug-in e trae vantaggio dalla spaziatura dei nomi con gli hook e che i membri privati ​​possono essere riutilizzati tra hook che non è possibile con le funzioni globali standard. Il seguente esempio di codice mostra il modello:

<?php
/** Plugin Headers ... */

return MyPlugin::bootstrap(); 

class MyPlugin
{
    /** @var MyPlugin */
    static $instance;
    static public function bootstrap() {
        if (NULL === self::$instance) {
            self::$instance = new __CLASS__;
        }
        return self::$instance;
    }
    # ...
}

Questo è un modello comune che uso per il file del plugin di base. La classe plugin da un lato rappresenta il plugin per wordpress e dall'altro consente di iniziare a utilizzare paradigmi orientati agli oggetti per il proprio codice che può anche essere completamente orientato agli oggetti (ma non è necessario). È una specie di controller, che si interfaccia con l'intera API wordpress come richiesta (e).

Come mostra l'esempio, verrà creata un'istanza del plugin. Ciò ti consente di utilizzare i beni comuni conosciuti come un Costruttore Documenti ( __construct) per inizializzare il plugin effettivo:

# ...
class MyPlugin
{
    # ...
    public function __construct()
    {
        add_filter('the_hook', array($this, 'hook'));
    }

    public function hook()
    {
    }
    # ...
}

Al momento della registrazione dell'hook, questo oggetto plug-in beneficia già del suo design: hai smesso di codificare la funzione hook reale rispetto al nome classe del plug-in concreto . Ciò è possibile a causa dell'associazione della classe all'istanza dell'oggetto per il callback. Sembra complicato, solo dicendo: $this è il plugin. Può essere utilizzato nei callback hook, confronta i metodi di registrazione della classe come callback hook .

Questo modello consente un'interfaccia più semplice con wordpress: l'iniezione è ridotta ai nomi degli hook e ai dati che forniscono. Puoi quindi iniziare a implementare direttamente in questa classe di plug-in o a riformattare la tua implementazione contro di essa, in modo da mettere solo il codice nella classe di plug-in che è il minimo indispensabile per definire l'interfaccia dei plug-in contro wordpress, ma tieni la logica generale da parte di worpdress. È qui che inizia il divertimento e molto probabilmente quello che ogni autore di plugin vuole raggiungere nel lungo periodo.

Quindi non programmare con worpdress ma contro di esso. Poiché worpdress è abbastanza flessibile, non esiste un'interfaccia comune o facile da descrivere per la programmazione. Una classe di plugin di base può assumere questo ruolo, offrendoti una maggiore flessibilità per il tuo codice, il che porterà a un codice più semplice e a prestazioni migliori.

Quindi non c'è solo un vantaggio per la spaziatura dei nomi. Il miglior suggerimento che posso dare è: mettiti alla prova. Non c'è molto che perderai, solo nuove cose da scoprire.

Molto probabilmente noterai differenze dopo aver superato alcuni altri importanti aggiornamenti di wordpress mantenendo compatibile il tuo plug-in.

Avvertenza : se il plug-in si integra direttamente con wordpress per completare il lavoro, l'utilizzo di una o due funzioni pubbliche potrebbe adattarsi meglio a te. Prendi lo strumento giusto per il lavoro.


1
Se le funzioni di classe statiche non sono in realtà diverse dalle funzioni globali e il tuo obiettivo è prevenire conflitti di spaziatura, non ho davvero capito la necessità (ancora) di passare a scrivere plugin come classi. Inoltre, sono confuso dalla tua funzione di bootstrap helper. Perché non dichiarare semplicemente il nuovo oggetto come $ new_object = new MyClass () ;?
AlxVallejo,

@AlxVallejo: solo per lo spazio dei nomi, non c'è vera necessità (come ho scritto nella risposta, i metodi di classe statica sono praticamente gli stessi delle funzioni globali). Quindi puoi fare il tuo spazio dei nomi (il tipo di spazio dei nomi pre PHP 5.3 che è). Quindi l'hai notato perfettamente. Simile alla funzione bootstrap statica: tecnicamente non è necessario, lo fa anche un semplice return $myPlugin = new MyPlugin(); . Tuttavia, per un quadro più ampio, un semplice nuovo potrebbe non essere sufficiente, confronta il plugin WordPress: come posso evitare un "accoppiamento stretto"? .
Hakre,

9

Classi VS set di funzioni


Prestazione

Generale: Afaik, non ci sono differenze nelle "prestazioni" tra classi e set di funzioni.

Dettaglio:

  • C'è una grande differenza se metti in discussione function_exists()vs. class_exists()normalmente hai molte funzioni (~ 1.800 (?) Nel core di wp) rispetto alle classi (~ 100 (?) Nel core di wp). Quindi rendere le cose "collegabili" e quindi mettere in discussione l'esistenza è una differenza nei tempi di esecuzione.
  • Le classi offrono un grande vantaggio rispetto ai set di funzioni: è molto più facile evitare di chiamarlo su una richiesta dove non è necessario, quindi con le funzioni. Devi solo fare controlli condizionali per la classe e non per ogni funzione. Quindi, se non ne hai bisogno ad ogni caricamento della pagina e puoi evitare di chiamare molte istruzioni if ​​/ else, una funzione "funziona meglio".

Architettura - Come funzionano le cose:

set di funzioni: in generale, le funzioni vengono eseguite nella riga chiamata. Quindi ogni volta che chiami cose, devi scriverle di nuovo, se devi chiamarle più di una volta.

Classe: ci sono diversi approcci alle classi. La classe più vicina a un set di funzioni è la classe "factory" ( wikipedia / google ). Imo è quasi uguale a un insieme di funzioni, ma incapsulato in una classe. Ma ci sono anche altri "tipi" di classi. Ad esempio, potresti scrivere un abstract o una classe di classe genitore, che estendi con una classe figlio. In un esempio del mondo reale: supponiamo che tu abbia una classe che costruisce alcuni campi di testo statici. Nella tua __construct()funzione hai una serie di scenari come "left_column", "right_column" e "footer_field". Quindi chiami qualcosa del tipo $text_field = new TextFieldClass();per istanziare la classe. E più tardi chiami semplicemente $text_field->add( $case => 'left_column', 'case' => 'foo text' );e$text_field->add( $case => 'footer_field', 'case' => 'bar text' );. Quindi tutti i tuoi condizionali e altro sono già stati eseguiti quando hai istanziato la classe e solo le due funzioni della classe sarebbero state chiamate quando hai creato i campi di testo. In questo szenario avresti potuto risparmiare alcuni ms di tempo di esecuzione.


Opinione personale

Se scrivi le tue lezioni con saggezza, avrai un piccolo vantaggio in termini di prestazioni. Ma avrai una struttura ben organizzata su cui lavorare. Finora niente di spettacolare. Ma se consideri i seguenti casi d'uso "divisi" per le classi e le funzioni in un plugin, otterrai il mio ultimo punto: la classe è interna, le funzioni sono API . Fintanto che offri l'API solo tramite funzioni utilizzabili pubblicamente (che quindi chiamano classi o funzioni di classe), sarai dalla parte del salvataggio sviluppando ulteriormente il tuo plugin. Hai ottenuto la libertà di cambiare la struttura interna o anche le possibilità del tuo plugin senza influenzare gli utenti sempre e ovunque.

Esempio:

// construction of object
if ( ! class_exists( 'WPSE_HelloWorld' ) )
{

class WPSE_HelloWorld
{
    function __construct( $args = array( 'text', 'html', 'echo' ) )
    {
        // call your object building procedures here
        $this->hello_world( 'text', 'html', 'echo' );
    }

    function hello_world( 'text', 'html', 'echo' )
    {
        $start_el = '<{$html}>';
        $end_el = '</{$html}>';
        if ( $echo )
        {
            return print "{$start_el}{$some}{$end_el}";
        }

        return "{$start_el}{$some}{$end_el}";
    }
} // END Class 

}

// API: public functions
function the_hello_world( $args( 'echo' => true ) )
{
    $new = new WPSE_HelloWorld();
    return $new->hello_world( $args );
}

function get_hello_world( array( $args( 'echo' => false) ) )
{
    $new = new WPSE_HelloWorld();
    return $new->hello_world( $args );
}

// then you can call it like get_the_title() or the_title(), which you know from the WP API:
// 'echo' is set to false per default:
$some_var = get_hello_world( array( 'text' => 'hello reader', 'html' => 'strong' ) );
# *returns* "<strong>hello reader</strong>"

// 'echo' is set to true per default:
the_hello_world( array( 'text' => 'hello reader', 'html' => 'strong' ) );
# *prints/echos* "<strong>hello reader</strong>"

Nota: leggere anche il link @ t310s pubblicato nel commento al Q.


solo curioso, perché ti aspetti che il tuo file plugin sia incluso più di una volta con wordpress?
Hacre,

@hakre Dove ho detto esattamente questo? triste, piuttosto stanco della mamma.
Kaiser,

1
@kaiser, suppongo che @hakre si riferisca alla if( ! class_exists )linea che hai all'inizio?
jjeaton,

1
@hakre Presumo che @kaiser stia facendo il class_existscontrollo non perché potrebbe essere incluso più di una volta ma per evitare un conflitto con un'altra classe?
Michal Mau,

Sì, mi stavo chiedendo dei class_exists.
Hacre,

4

È una scelta puramente stilistica da parte dell'autore del plugin. Non c'è una vera differenza in termini di velocità.


1

Le lezioni di solito non offrono alcun vantaggio in termini di prestazioni, ma molto raramente hanno anche effetti negativi. Il loro vero vantaggio è quello di rendere il codice più chiaro ed evitare conflitti nello spazio dei nomi.


Tuttavia, come menzionato @hakre, i conflitti dello spazio dei nomi non sono in realtà diversi quando si usano i prefissi per le funzioni globali. Codice "più pulito" e prevenzione dei conflitti nello spazio dei nomi sono sinonimi in questo caso, no?
AlxVallejo,

@AlxVallejo immagino di sì :)
Bainternet il

0

La maggior parte delle volte, se usi le funzioni, inserirai il nome del plugin in ogni nome di funzione, così efficacemente, duplicherai quel nome una dozzina di volte se il plugin ha una dozzina di funzioni che è un po 'un trascinamento .

Con le classi, avresti probabilmente il nome del plugin nel nome della classe probabilmente una volta.

Inoltre, è possibile utilizzare l'ereditarietà o altri costrutti oo per implementare comportamenti in modo molto pulito. Ecco un ex:

class animalplugin{
  //plugin functions...
  function talk(){print "animalnoise";}
}
class animalplugin_with_cat_mods extends abcplugin{
  //cat functions overrides
  function talk(){print "meow";}
}
if (iscat()){
  new animalplugin_with_cat_mods();
} else {
  new animalplugin();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.