Статьи

Два способа разработки плагинов WordPress: функциональное программирование

Во второй части серии рассматриваются два разных стиля программирования (иногда называемые парадигмами программирования), которые вы можете использовать при написании плагинов WordPress. В первой части Том Макфарлин рассмотрел объектно-ориентированное программирование. В этой части мы рассмотрим функциональное программирование.

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


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

Функциональное программирование подчеркивает оценку функций и избегает понятия состояний или объектов в отличие от объектно-ориентированного программирования, которое поощряет думать о коде как о воздействии на объект (ы), использовании методов для изменения этих объектов или взаимодействия с ними. Давайте посмотрим на очень простой пример, сравнивающий два стиля:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Functional method
function add_two( $n ) {
    return $n +2;
}
 
$a = 2;
$b = add_two( $a );
 
 
// Object oriented method
class Number {
    var $value = 0;
 
    function __construct( $a ) {
        $this->value = $a;
    }
 
    function add_two() {
        $this->value = $this->value +2;
    }
}
 
$a = new Number( 2 );
echo $a->value;
$a->add_two();
echo $a->value;

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


Определение функций очень просто:

1
2
3
4
5
6
7
function add( $number, $number2 = 1 ) {
    // Perform code acting on passed variables
    $sum = $number + $number2;
 
    // Optional, if needed you can return a value
    return $sum;
}

Как только функция объявлена, она может использоваться в любом месте вашего плагина — другими словами, она имеет глобальную область видимости.

1
2
3
$a = 4;
$b = 7;
echo add( $a, $b );
Функции должны иметь уникальные имена. Переопределение функции приведет к ошибке. Поскольку ваш код будет работать вместе с другими плагинами, темами и самим WordPress, вы никогда не должны использовать общие имена. Вместо этого вам следует добавлять префиксы имен ваших функций к чему-то уникальному (например, к имени вашего плагина).

Возможно, вы заметили, что в определении add второй аргумент установлен равным 1 . Это устанавливает значение по умолчанию для $number2 (в данном случае 1) и делает аргумент необязательным. Если аргумент не указан, значение принимается за значение по умолчанию:

1
2
echo add( 4 );
echo add( 4, 1 );

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

1
echo add();

Вы также можете иметь переменное количество аргументов. Внутри функции мы можем использовать func_num_args() чтобы получить количество полученных аргументов, в то время как func_get_arg() позволяет вам получить доступ к определенной переданной переменной, индексированной с 0.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
function sum() {
    // Get the number of arguments given to sum()
    $number_args = func_num_args();
 
    $sum = 0;
 
    if ( ! $number_args )
        return $sum;
 
    for ( $i = 0; $i < $number_args; $i++ ) {
        $sum += func_get_arg( $i );
    }
 
    return $sum;
}
 
echo sum( 1, 2, 3, 4 );
echo sum( 1, 2 );
echo sum();

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

01
02
03
04
05
06
07
08
09
10
$a = ‘Hello’;
$b = ‘World’;
function hello_world() {
    // This is necessary to access $a and $b
    // declared outside of the function scope.
    global $a, $b;
    $b = $a .
}
hello_world();
echo $b;
Использование глобалов, как правило, не рекомендуется. В частности, поскольку два плагина, использующие одно и то же имя для глобальной переменной, могут привести к поломке одного или обоих плагинов. Если вам необходимо использовать глобальную переменную, снова убедитесь, что она уникальна, добавив префикс с именем вашего плагина.

Решение о том, какой стиль программирования использовать, сводится к суждению — и да — к личным предпочтениям. Правильнее или неправильнее использовать функциональное, а не объектно-ориентированное программирование, но чаще всего существует один стиль, который лучше подходит для того, чего вы пытаетесь достичь.

Иногда объектно-ориентированное программирование просто не нужно, а только усложняет или вводит лишний код. Примером могут служить различные «служебные» функции, предоставляемые WordPress. Это общие функции, которые служат для выполнения определенной цели. Например, wp_trim_words( $text, $num_words ) просто обрезает заданную строку до определенного размера (в словах). Это не добавит ничего, чтобы определить wp_trim_words() вместо этого как метод, принадлежащий некоторому объекту, и приведет к более уродливому коду. При функциональном программировании это занимает одну строку.

Одним из преимуществ функционального программирования, особенно для начинающих, является его простота. Вам не нужно беспокоиться о статических, частных или защищенных функциях — все они глобальные. Также не существует понятия статических переменных. На самом базовом уровне ваша функция возвращает вывод, полученный из того, что вы ей дали. Например, get_the_title( 7 ) вернет заголовок сообщения с идентификатором 7.

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

01
02
03
04
05
06
07
08
09
10
class DemoPlugin {
    public function __construct() {
        add_action( ‘wp_enqueue_scripts’, array( $this, ‘register_plugin_scripts’ ) );
    }
 
    public function register_plugin_scripts() {
        // Register plugin scripts
    }
}
$demo_plugin = new DemoPlugin();

Когда WordPress сохраняет метод register_plugin_scripts() чтобы его можно было вызывать при wp_enqueue_scripts действия wp_enqueue_scripts , он делает это, ссылаясь не только на метод, но и на объект $demo_plugin . Это связано с тем, что один и тот же метод для разных экземпляров объекта считается разными методами, то есть $demo_plugin->register_plugin_scripts() и $copy_of_demo_plugin->register_plugin_scripts() не являются одинаковыми. Это может показаться странным — но методы могут вести себя по-разному для разных экземпляров одного и того же класса, поэтому нам нужно ссылаться как на метод, так и на экземпляр.

Но почему это важно? Стороннему плагину или теме очень трудно отсоединить этот метод, поскольку для этого им нужно будет вызвать:

1
remove_action( ‘wp_enqueue_scripts’, array( $demo_plugin, ‘register_plugin_scripts’ ) );

Но в целом они не будут иметь доступа к переменной $demo_plugin . (Примечание: если метод объявлен как статический, вы можете обойти это).


Конечно, у объектно-ориентированного программирования есть свои преимущества, о которых говорилось в первой части. Как также отметил Том, это неизбежно при использовании API виджетов WordPress. Другой распространенный пример — WP_Query() . Здесь объектно-ориентированный подход явно лучший: у вас есть объект (в данном случае запрос), который имеет различные свойства (например, критерии поиска, информация о разбиении на страницы, результаты сопоставления), и вы хотите выполнить этот запрос (проанализировать его, сгенерировать и очистить соответствующий SQL, и вернуть результаты).

WP_Query() демонстрирует, насколько мощным может быть объектно-ориентированное программирование при правильном использовании. После инициирования запроса:

1
$the_query = new WP_Query( array(…) );

Вы можете получить доступ не только к результатам, но и к другой информации, такой как значения нумерации страниц: сколько страниц результатов имеется, какую страницу просматривают, общее количество результатов и тип запроса, например, $the_query->is_search() , $the_query->is_single() и т. д. Существует также вся инфраструктура ‘loop’;

1
2
3
4
5
6
7
8
9
if ( $the_query->have_posts() ) {
    echo ‘<ul>’;
    while( $the_query->have_posts() ): $the_query->the_post();
        // The Loop
        echo ‘<li>’ .
    endwhile;
    echo ‘</ul>’;
}
wp_reset_postdata();

Который скрывает всю внутреннюю манипуляцию результатами и глобальности за дружественным к человеку API.

Так что насчет get_posts() ? Это просто служит оболочкой для WP_Query() и просто возвращает массив сообщений, соответствующих запросу. Таким образом, вы не получаете «наворотов» WP_Query() , но это немного более эффективно. Поэтому, следует ли вам использовать get_posts() или WP_Query() зависит от вашего WP_Query() использования (например, требуется ли разбиение на страницы или нет), но это также зависит от личных предпочтений.

1
2
3
4
5
6
7
8
9
$results = get_posts( array( … ) );
 
if ( $results ) {
    echo ‘<ul>’;
    foreach( $results as $the_post ) {
        echo ‘<li>’ .
    }
    echo ‘</ul>’;
}

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