Чи слід усі плагіни інкапсулювати в класі?


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_ через помилкові позитиви. Але в підсумку різниці не дуже.

Ключовим моментом є: функції статичного класу Документи насправді не багато, ніж глобальні функції Документи .

І цей приклад також показує: Простір імен нормально, але з текстовою адресою проміжок імен припиняється за допомогою гачків: Функція зворотного виклику жорстко кодується, отже, перевага в просторі імен за допомогою класу (одне місце для базового імені, імені класу) не відповідає допоможіть, коли ви втручаєтесь у свій код за допомогою wordpress для назв гака.

Реальна користь починається з використання фактичних екземплярів класу та нестатичних функцій. Це має ту перевагу, що ви можете почати використовувати принципи ОО і можете впорядкувати свій код. Функції статичного класу - це скоріше проблема, ніж інфакт рішення.

Тоді це більше, ніж просто синтаксичний цукор.

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

Один поширений підхід, який я маю навіть з меншими плагінами, - це використовувати статичну функцію помічника для інстанціювання плагіна, а решта знаходиться тоді в екземплярі плагіна. Це допомагає інкапсулювати основну логіку плагіна, і це вигідно від простору імен за допомогою гачків, а також, що приватні члени можуть бути повторно використані між гачками, що неможливо зі стандартними глобальними функціями. Наступний приклад коду показує шаблон:

<?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, але зберігати загальну логіку в стороні від worddress. Ось тут починається веселощі, і, швидше за все, те, чого хоче досягти кожен автор плагінів у довгостроковій перспективі.

Тому не програмуйте за допомогою програми, а проти цього. Оскільки реферат є досить гнучким, немає загального або простого для опису інтерфейсу для програмування проти. Базовий клас плагінів може взяти на себе цю роль, дозволяючи вам більше гнучкості для власного коду, що призведе до більш легкого коду та кращої продуктивності.

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

Ви, ймовірно, помітите відмінності після того, як пройдете кілька основних оновлень Wordpress, зберігаючи плагін сумісним.

Caveat : Якщо ваш плагін безпосередньо інтегрується з wordpress, щоб виконати роботу, використання однієї або двох загальнодоступних функцій може підійти вам краще. Візьміть правильний інструмент для роботи.


1
Якщо функції статичного класу насправді нічим не відрізняються від глобальних функцій, і ваша мета - запобігти конфліктам між просторами імен, я дійсно не зрозумів необхідності (поки) перейти до написання плагінів як класів. Також мене бентежить ваша допоможна завантажувальна функція. Чому б просто не оголосити новий об’єкт як $ new_object = new MyClass () ;?
AlxVallejo

@AlxVallejo: В самому просторі імен немає справжньої необхідності (як я писав у відповіді, методи статичного класу майже однакові як глобальні функції). Таким чином, ви можете зробити простору імен самостійно (попередній тип PHP 5.3 - такий проміжок імен). Тож ви помітили це абсолютно правильно. Аналогічно статичній функції завантаження: Технічно це не потрібно, простий return $myPlugin = new MyPlugin(); робить це також. Однак для більшої картини простого нового може бути недостатньо, порівняйте плагін WordPress: Як я можу уникнути "жорсткої зв'язку"? .
hakre

9

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


Продуктивність

Загальне: Afaik, різниці в "продуктивності" між класами та наборами функцій немає.

Детальніше:

  • Існує велика різниця, якщо ви ставите під сумнів function_exists()проти, class_exists()як зазвичай, у вас є багато функцій (~ 1.800 (?) В wp core) проти класів (~ 100 (?) В wp core). Тож зробити речі "підключеними" і, таким чином, ставити під сумнів існування - це різниця у часі виконання.
  • Класи пропонують одну велику перевагу перед наборами функцій: Ви можете набагато простіше уникнути виклику його за запитом там, де вам це не потрібно, а потім за допомогою функцій. Вам потрібно робити лише умовні перевірки для класу, а не для кожної функції. Отже, якщо він вам не потрібен при кожному завантаженні сторінки, і ви можете уникнути виклику безлічі висловлювань if / else, функція "працює краще".

Архітектура - як працюють речі:

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

Клас: Є різні підходи до занять. Клас, який найближче до набору функцій - це "заводський" клас ( wikipedia / google ). Imo, це майже те саме, що набір функцій, але інкапсульований у класі. Але є й інші "типи" занять. Наприклад, ви можете написати абстрактний або батьківський клас класу, який ви поширюєте з дочірнім класом. На прикладі реального світу: Скажімо, ви отримали клас, який будує деякі статичні текстові поля. У своїй __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' );. Тоді всі ваші умовні умови та інше вже були виконані, коли ви інстанціювали клас, і тільки дві функції класу були б викликані при складанні текстових полів. У цьому szenario ви могли зекономити кілька мс часу виконання.


Особиста думка

Якщо ви грамотно пишете свої заняття, то у вас буде незначна перевага у виконанні. Але у вас буде добре організована структура, над якою можна працювати. Поки що нічого вражаючого. Але якщо ви розглянете наступні "розділені" випадки використання для класів і функцій у плагіні, то ви отримаєте мою остаточну точку: Клас внутрішній, функції - 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

@hakre Де саме я це сказав? сирий, досить втомився від мами.
кайзер

1
@kaiser, я припускаю, що @hakre має на увазі if( ! class_exists )рядок, який ви маєте на початку?
jjeaton

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

Так, мені було цікаво про class_exists.
hakre

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.