Todos os plugins devem ser encapsulados em uma classe?

28

Ao desenvolver um plug-in, as funções devem ser agrupadas em uma Classe para evitar conflitos de namespace?

O uso de classes cria sobrecarga de desempenho para PHP?

Se houver um impacto no desempenho, os nomes das funções devem ser pré-fixados?

Jamie
fonte
8
Provavelmente mais uma pergunta sobre PHP do que uma sobre WordPress, veja se esta questão sobre o Stackoverflow atende adequadamente à sua pergunta.
t31os

Respostas:

24

Ao desenvolver um plug-in, as funções devem ser agrupadas em uma Classe para evitar conflitos de namespace?

Sim, mas esse é apenas um dos argumentos menores. De fato, essa não é a natureza "verdadeira" de uma classe no OOAD .

O uso de classes cria sobrecarga de desempenho para PHP?

Não, notavelmente. O design inadequado e / ou o código escrito incorreto ou a otimização antecipada criam muito mais problemas de desempenho do que os recursos reais do idioma.

Se houver um impacto no desempenho, os nomes das funções devem ser pré-fixados?

Como está escrito, não há desempenho atingido. Um código gravado incorreto será mais prejudicial ao desempenho do que um código gravado que possui mais linhas de código, mas não o força a fazer coisas ruins.


Bottom Line:

Você pode usar classes de maneira diferente para plug-ins. Você pode apenas usá-los para ter algum tipo de espaço para nome e usá-los "apenas" para funções globais. A forma mais direta disso são funções de classe estática, o seguinte exemplo de código mostra as duas primeiras funções globais e depois as funções de classe estática global:

/* 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');

Este é apenas um pequeno exemplo mostrando que você precisa digitar mais para o gancho único. Além disso, ele mostra como o namespacing funciona: Você pode substituir com mais facilidade o nome de classe única para renomear todas as funções estáticas e, em seguida, procurar e substituir myplug::quais seriam mais difíceis myplug_devido a falsos positivos. Mas no final não há muita diferença.

O ponto principal é: funções estáticas de classe Docs não são muito mais do que funções globais Docs .

E este exemplo também mostra: O namespacing é bom, mas com worpdress, o namespacing para com o uso de hooks: A função de retorno de chamada é codificada, portanto, o benefício no namespacing usando a classe (um local para o nome base, o nome da classe) não ajuda quando você intervém seu código com o wordpress para os nomes dos ganchos.

O benefício real começa com o uso de instâncias de classe reais e funções não estáticas. Isso tem o benefício de que você pode começar a usar os princípios OO e pode otimizar seu código. Funções de classe estática são mais um problema do que uma solução.

Então é mais do que apenas açúcar sintático.

O ponto principal é: faça algo que o ajude a escrever o código com o qual você possa lidar e manter facilmente. Não exagere no desempenho, isso é um erro comum. Mais importante é que você escreva um código fácil de ler e entender, que faça exatamente o que você precisa. Talvez esta pergunta e resposta sejam úteis para uma imagem maior neste contexto: Ajuda múltipla da Metabox personalizada .

Uma abordagem comum que tenho, mesmo com plug-ins menores, é usar uma função auxiliar estática para instanciar o plug-in e o restante reside na instância do plug-in. Isso ajuda a encapsular a lógica principal do plug-in e se beneficia do espaçamento de nomes com os ganchos, assim como membros privados podem ser reutilizados entre ganchos, o que não é possível com as funções globais padrão. O seguinte exemplo de código mostra o padrão:

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

Esse é um padrão comum que eu uso para o arquivo de plug-in base. A classe de plug-ins, por um lado, representa o plugin para wordpress e, por outro lado, permite começar a usar paradigmas orientados a objetos para o próprio código, que pode até ser completamente orientado a objetos (mas não precisa). É uma espécie de controlador, interagindo com toda a API do wordpress como o (s) pedido (s).

Como o exemplo mostra, uma instância do plugin será criada. Isso permite que você faça uso de bens comuns conhecidos como um Docs do Construtor ( )__construct para inicializar o plug-in real:

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

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

No momento em que o gancho é registrado, este objeto de plug-in já se beneficia do seu design: você deixou de codificar a função de gancho real com base no nome da classe do plug-in concreto . Isso é possível devido à ligação da classe à instância do objeto para o retorno de chamada. Parece complicado, apenas dizendo: $this é o plugin. Pode ser usado em retornos de chamada de gancho, compare os métodos da classe Registering como retornos de chamada de gancho .

Esse padrão permite uma interface mais fácil com o wordpress: a injeção é reduzida aos nomes dos ganchos e a quais dados eles fornecem. Você pode começar a implementar diretamente nesta classe de plug-in ou refatorar sua implementação, portanto, coloque apenas código na classe de plug-in que é o mínimo necessário para definir sua interface de plug-ins contra o wordpress, mas mantenha a lógica geral à parte do worpdress. É aqui que a diversão começa e provavelmente o que cada autor de plug-in deseja alcançar a longo prazo.

Portanto, não programe com worpdress, mas contra ela. Como o worpdress é bastante flexível, não há uma interface comum ou fácil de descrever para a qual programar. Uma classe de plug-in base pode assumir essa função, permitindo mais flexibilidade para seu próprio código, o que levará a um código mais fácil e a um melhor desempenho.

Portanto, há mais do que apenas um benefício no espaçamento de nomes. A melhor sugestão que posso dar é: Tente você mesmo. Não há muito a perder, apenas coisas novas a descobrir.

Você provavelmente notará diferenças depois de passar por algumas atualizações importantes do wordpress, mantendo seu plugin compatível.

Advertência : Se o seu plug-in se integra diretamente ao wordpress para fazer o trabalho, usar uma ou duas funções públicas pode ser mais adequado para você. Pegue a ferramenta certa para o trabalho.

hakre
fonte
1
Se as funções de classe estática realmente não diferem das funções globais, e seu objetivo é evitar conflitos de espaço para nome, eu realmente não entendi a necessidade (ainda) de passar a escrever plug-ins como classes. Além disso, estou confuso com a sua função de inicialização. Por que não declarar o novo objeto como $ new_object = new MyClass () ;?
AlxVallejo
@AlxVallejo: Apenas para namespacing, não há uma necessidade verdadeira (como escrevi na resposta, métodos de classe estática são praticamente os mesmos que funções globais). Então você pode fazer o seu próprio espaço para nome (o tipo de espaço para nome anterior ao PHP 5.3). Então você percebeu isso perfeitamente certo. Semelhante à função estática de autoinicialização: tecnicamente não é necessário, é simples return $myPlugin = new MyPlugin(); também. No entanto, para uma visão mais ampla, um simples novo pode não ser suficiente, compare o Plugin do WordPress: Como evitar o "acoplamento apertado"? .
hakre
9

Classes VS conjunto de funções


atuação

Geral: Afaik, não há diferença no "desempenho" entre classes e conjuntos de funções.

Detalhe:

  • Há uma grande diferença se você questionar function_exists()vs. class_exists()como normalmente você tem muitas funções (~ 1.800 (?) No wp core) vs. classes (~ 100 (?) No wp core). Portanto, tornar as coisas "conectáveis" e, portanto, questionar a existência é uma diferença no tempo de execução.
  • As classes oferecem uma grande vantagem sobre os conjuntos de funções: é muito mais fácil evitar chamá-lo em uma solicitação em que você não precisa, e depois em funções. Você só precisa fazer verificações condicionais para a classe e não para todas as funções. Portanto, se você não precisar disso em todo carregamento de página e puder evitar chamar muitas instruções if / else, uma função "terá um desempenho melhor".

Arquitetura - Como as coisas funcionam:

conjunto de funções: Em geral, as funções são executadas na linha que você chama. Então, toda vez que você liga para as coisas, você precisa escrevê-las novamente, se precisar chamá-las mais de uma vez.

Classe: Existem diferentes abordagens para as classes. A classe que mais se aproxima de um conjunto de funções é a classe "factory" ( wikipedia / google ). Imo é quase o mesmo que um conjunto de funções, mas encapsulado em uma classe. Mas existem outros "tipos" de classes também. Você poderia, por exemplo, escrever um resumo ou uma classe de classe pai, que você estende com uma classe filha. Em um exemplo do mundo real: digamos que você tenha uma classe que cria alguns campos de texto estático. Na sua __construct()função, você tem um conjunto de cenários como "left_column", "right_column" e "footer_field". Então você chama algo como $text_field = new TextFieldClass();instanciar a classe. E depois você simplesmente chama $text_field->add( $case => 'left_column', 'case' => 'foo text' );e$text_field->add( $case => 'footer_field', 'case' => 'bar text' );. Então todos os seus condicionais e outros já foram executados quando você instancia a classe e apenas as duas funções da classe seriam chamadas quando você cria os campos de texto. Nesse cenário, você poderia ter economizado alguns ms de tempo de execução.


Opinião pessoal

Se você escrever suas aulas com sabedoria, terá uma pequena vantagem no desempenho. Mas você terá uma estrutura bem organizada para trabalhar. Até agora nada de espetacular. Mas se você considerar os seguintes casos de uso "divididos" para classes e funções em um plug-in, obterá meu ponto final : Classe é interna, funções são API . Contanto que você ofereça API apenas através de funções publicamente utilizáveis ​​(que então chamam classes ou funções de classe), você estará no lado de salvar, desenvolvendo ainda mais seu plug-in. Você adquiriu a liberdade de alterar a estrutura interna ou mesmo as possibilidades do seu plug-in sem afetar os usuários a qualquer momento e em qualquer lugar.

Exemplo:

// 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: Leia também o link @ t310s publicado no comentário ao Q.

kaiser
fonte
Só por curiosidade, por que você espera que seu arquivo de plug-in seja incluído mais de uma vez no wordpress?
hakre
@hakre Onde exatamente eu disse isso? sry, muito cansado com a mãe.
Kaiser
1
@ Kaiser, eu assumo @hakre está se referindo à if( ! class_exists )linha que você tem no início?
jjeaton
1
@hakre Presumo que o @kaiser esteja fazendo a class_existsverificação não porque poderia ser incluída mais de uma vez, mas para evitar um conflito com outra classe?
Michal Mau
Sim, eu queria saber sobre a classe_existe.
hakre
4

É uma escolha puramente estilística por parte do autor do plugin. Não há diferença real em termos de velocidade.

Otto
fonte
1

As aulas geralmente não oferecem benefícios em termos de desempenho, mas também raramente têm efeitos negativos. Seu benefício real é tornar o código mais claro e evitar conflitos de namespace.

Bainternet
fonte
No entanto, como o @hakre mencionou, o conflito de namespace não é realmente diferente ao usar prefixos em funções globais. Código "mais limpo" e prevenção de conflitos de namespace são sinônimos neste caso, não?
AlxVallejo
@AlxVallejo Acho que sim :)
Bainternet
0

Na maioria das vezes, se você usar funções, você colocará o nome do plug-in em cada nome de função; assim, duplicará esse nome uma dúzia de vezes se o plug-in tiver uma dúzia de funções, o que é um pouco chato .

Com as classes, você provavelmente terá o nome do plug-in no nome da classe provavelmente uma vez.

Além disso, você pode usar herança ou outras construções oo para implementar comportamentos de uma maneira muito limpa. Aqui está um 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();
}
zeedre
fonte