Должны ли все плагины быть инкапсулированы в класс?


28

При разработке плагина функции должны быть сгруппированы в класс, чтобы избежать конфликтов пространства имен?

Создает ли использование классов снижение производительности для PHP?

Если производительность падает, имена функций должны быть предварительно фиксированными?


8
Возможно, это больше вопрос PHP, чем вопрос WordPress, посмотрите, подходит ли этот вопрос Stackoverflow к вашему вопросу.
t31os

Ответы:


24

При разработке плагина функции должны быть сгруппированы в класс, чтобы избежать конфликтов пространства имен?

Да, но это только один из второстепенных аргументов. Фактически, это не «истинная» природа класса в OOAD .

Создает ли использование классов снижение производительности для PHP?

Нет, не особенно. Плохой дизайн и / или плохо написанный код или преждевременная оптимизация создают гораздо больше проблем с производительностью, чем реальные языковые возможности

Если производительность падает, имена функций должны быть предварительно фиксированными?

Как написано, производительности нет. Плохо написанный код будет скорее ударом по производительности, чем хорошим написанным кодом, который содержит еще несколько строк кода, но не заставляет вас делать плохие вещи.


Нижняя граница:

Вы можете по-разному использовать классы для плагинов. Вы можете просто использовать их, чтобы иметь какое-то пространство имен, и использовать их «просто» для глобальных функций. Наиболее прямой формой этого являются статические функции класса, в следующем примере кода показаны обе: сначала глобальные функции, затем глобальные статические функции класса:

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

Это всего лишь небольшой пример, показывающий, что вам нужно набрать больше для единственного хука. Кроме того, он показывает, как работает пространство имен: Вы можете легко заменить одно имя класса, чтобы переименовать все статические функции, а затем искать и заменять, myplug::что может быть сложнее myplug_из-за ложных срабатываний. Но, в конце концов, нет большой разницы.

Ключевым моментом является то, что статические функции класса Docs не намного больше, чем глобальные функции Docs .

И этот пример также показывает: Пространство имен в порядке, но с worpdress, пространство имен останавливается с использованием хуков: функция обратного вызова жестко закодирована, поэтому преимущество в пространстве имен с использованием класса (одно место для base-name, classname) не помочь, когда вы вводите свой код с WordPress для имен хуков.

Реальное преимущество начинается с использования реальных экземпляров классов и нестатических функций. Это дает то преимущество, что вы можете начать использовать принципы ОО и оптимизировать свой код. Статические функции класса являются скорее проблемой, чем решением проблемы.

Тогда это больше, чем просто синтаксический сахар.

Ключевой момент: сделайте то, что поможет вам написать код, с которым вы легко сможете справиться и поддерживать. Не переоценивайте производительность, это распространенная ошибка. Более важно то, что вы пишете код, который легко читать и понимать, который просто делает то, что вам нужно. Может быть, этот вопрос и ответ полезны для большей картины в этом контексте: Справка по нескольким настраиваемым Metabox .

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

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

Это общий шаблон, который я использую для базового файла плагина. Класс плагина, с одной стороны, представляет собой плагин для WordPress, а с другой стороны, он позволяет начать использовать объектно-ориентированные парадигмы для собственного кода, который может быть даже полностью объектно-ориентированным (но не обязательным). Это своего рода контроллер, взаимодействующий со всем API WordPress как запрос (ы).

Как показывает пример, будет создан экземпляр плагина. Это позволяет вам использовать известные общие ресурсы, такие как Constructor Docs ( __construct), для инициализации реального плагина:

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

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

В то время, когда ловушка зарегистрирована, этот объект плагина уже получает выгоду от своего дизайна: вы перестали жестко кодировать реальную функцию ловушки против конкретного имени класса плагина . Это возможно из-за привязки класса к экземпляру объекта для обратного вызова. Звучит сложно, просто сказать: $this это плагин. Может использоваться в обратных вызовах хуков, сравните методы регистрации класса как обратные вызовы хуков .

Этот шаблон позволяет упростить взаимодействие с WordPress: инъекция сводится к именам хуков и тем, какие данные они предоставляют. Затем вы можете начать внедрять непосредственно в этот класс плагинов или реорганизовать свою реализацию против него, чтобы поместить код только в класс плагинов, который является минимальным для определения интерфейса ваших плагинов для WordPress, но оставьте общую логику в стороне от worpdress. Именно здесь начинается самое интересное, и, скорее всего, этого хочет добиться каждый автор плагина в долгосрочной перспективе.

Так что не программируйте с worpdress, а против него. Поскольку worpdress достаточно гибок, нет общего или простого описания интерфейса для программирования. Базовый класс плагинов может взять на себя эту роль, предоставляя вам большую гибкость для вашего собственного кода, что приведет к упрощению кода и повышению производительности.

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

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

Предостережение : если ваш плагин напрямую интегрируется с WordPress для выполнения работы, использование одной или двух открытых функций может вам подойти. Возьмите правильный инструмент для работы.


1
Если статические функции классов на самом деле ничем не отличаются от глобальных функций, и ваша цель - предотвратить конфликты пространств имен, я действительно не понял необходимости (пока) переключиться на написание плагинов в качестве классов. Кроме того, меня смущает ваша вспомогательная функция начальной загрузки. Почему бы просто не объявить новый объект как $ new_object = new MyClass () ;?
AlxVallejo

@AlxVallejo: Только для пространств имен нет реальной необходимости (как я писал в ответе, методы статического класса во многом аналогичны глобальным функциям). Таким образом, вы можете создать собственное пространство имен (это пространство имен до PHP 5.3). Итак, вы заметили, что совершенно правильно. Аналогично статической функции начальной загрузки: технически это не нужно, простой return $myPlugin = new MyPlugin(); тоже делает это. Однако для более широкой картины простого нового может быть недостаточно, сравните плагин WordPress: как избежать «тесной связи»? ,
Хакре

9

Классы VS набор функций


Спектакль

Общие сведения: Afaik, нет никакой разницы в «производительности» между классами и наборами функций.

Деталь:

  • Существует большая разница, если вы спрашиваете function_exists()против, class_exists()как обычно, у вас есть много функций (~ 1.800 (?) В ядре wp) против классов (~ 100 (?) В ядре wp). Поэтому создание вещи «подключаемой» и, следовательно, сомнение в существовании - это разница во времени выполнения.
  • Классы предлагают одно большое преимущество по сравнению с наборами функций: гораздо проще избежать вызова по запросу, когда он вам не нужен, чем с помощью функций. Вам нужно только выполнить условные проверки для класса, а не для каждой функции. Так что если вам не нужно это при каждой загрузке страницы и вы можете избежать вызова большого количества операторов if / else, функция «работает лучше».

Архитектура - Как все работает:

набор функций: в общем случае функции выполняются в строке, которую вы вызываете. Таким образом, каждый раз, когда вы звоните, вы должны написать это снова, если вам нужно звонить более одного раза.

Класс: Есть разные подходы к классам. Класс, который ближе всего подходит к набору функций, это класс «фабрика» ( wikipedia / google ). На мой взгляд, это почти то же самое, что и набор функций, но заключено в класс. Но есть и другие «типы» классов. Например, вы можете написать реферат или класс родительского класса, который вы расширяете с помощью дочернего класса. Пример из реальной жизни: допустим, у вас есть класс, который строит некоторые статические текстовые поля. В вашей __construct()функции у вас есть набор сценариев, таких как "left_column", "right_column" и "footer_field". Затем вы вызываете что-то вроде $text_field = new TextFieldClass();создания экземпляра класса. А потом вы просто позвоните $text_field->add( $case => 'left_column', 'case' => 'foo text' );и$text_field->add( $case => 'footer_field', 'case' => 'bar text' );, Тогда все ваши условные выражения и все остальное уже были выполнены, когда вы создали экземпляр класса, и только две функции класса были бы вызваны при создании текстовых полей. В этом сценарии вы могли бы сэкономить несколько мс времени выполнения.


Личное мнение

Если вы будете писать уроки с умом, у вас будет небольшое преимущество в производительности. Но у вас будет хорошо организованная структура для работы. Пока ничего впечатляющего. Но если вы рассмотрите следующие «разделенные» варианты использования для классов и функций в плагине, то вы получите мой последний вывод: класс является внутренним, функции - API . Пока вы предлагаете API только через общедоступные функции (которые затем вызывают классы или функции классов), вы будете на стороне сохранения в дальнейшем развитии вашего плагина. Вы получили свободу изменять внутреннюю структуру или даже возможности вашего плагина, не влияя на пользователей в любое время и в любом месте.

Пример:

// 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>"

Примечание: Пожалуйста, прочитайте также ссылку @ t310s, размещенную в комментарии к Q.


просто любопытно, почему вы ожидаете, что ваш файл плагина будет включен в Wordpress несколько раз?
Хакре

@hakre Где именно я это сказал? очень, очень устал от мамы.
Кайзер

1
@ Кайзер, я полагаю, @hakre имеет в виду if( ! class_exists )строку, которая у тебя есть в начале?
jjeaton

1
@hakre Я предполагаю, что @kaiser выполняет class_existsпроверку не потому, что она может быть включена более одного раза, а чтобы избежать конфликта с другим классом?
Михал Мау

Да, я задавался вопросом о class_exists.
Хакре

4

Это чисто стилистический выбор со стороны автора плагина. Там нет никакой разницы в скорости.


1

Классы обычно не дают никаких преимуществ с точки зрения производительности, но они также очень редко имеют какие-либо негативные последствия. Их реальное преимущество заключается в том, чтобы сделать код более понятным и избежать конфликтов пространства имен.


Тем не менее, как упоминал @hakre, конфликты пространства имен на самом деле ничем не отличаются при использовании префиксов в глобальных функциях. «Чистый» код и предотвращение конфликтов пространства имен являются синонимами в этом случае, нет?
AlxVallejo

@AlxVallejo я так думаю :)
Bainternet

0

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

С классами у вас будет просто имя плагина в названии класса.

Кроме того, вы можете использовать наследование или другие oo-конструкции для очень простой реализации поведения. Вот бывший:

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();
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.