Во второй части серии рассматриваются два разных стиля программирования (иногда называемые парадигмами программирования), которые вы можете использовать при написании плагинов 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 );
|
Возможно, вы заметили, что в определении 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
. (Примечание: если метод объявлен как статический, вы можете обойти это).
Объектно-ориентированное и функциональное программирование в WordPress
Конечно, у объектно-ориентированного программирования есть свои преимущества, о которых говорилось в первой части. Как также отметил Том, это неизбежно при использовании 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>’;
}
|
Резюме
Надеемся, что эти две статьи помогли выделить преимущества и недостатки этих стилей программирования. Суть в том, что здесь нет правильного и неправильного, и у каждого программиста будут свои личные предпочтения. Но некоторые контексты более легко поддаются определенному стилю программирования — и поэтому вы должны ожидать, что ваш плагин будет содержать смесь обоих.