Почему WordPress-разработчик должен разбираться в объектно-ориентированном программировании

Дата публикации:Сентябрь 26, 2015

oop

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

Объе́ктно-ориенти́рованное программи́рование (ООП) — парадигма программирования, в которой основными концепциями являются понятия объектов и классов. В случае языков с прототипированием вместо классов используются объекты-прототипы.

Вы говорите себе, что объектно-ориентированное программирование не слишком полезно и не стоит затраченных усилий. Цель этой статьи состоит в том, чтобы разъяснить вам его значение. К концу статьи у вас должно сложиться четкое понимание того, почему вы должны изучить ООП.

Уточняем ожидания

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

Вы изучили документацию по PHP или статью по теме. Вы поместили ваши функции в класс для ваших плагинов. В конце концов, это именно то, что вытекает из документации WordPress. Почувствовали ли вы, что сделали вещи лучше? Поняли ли вы, почему вы так сделали? Скорее всего, нет.

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

Начнем с того, что вы знаете

Если бы я попросил вас объяснить мне, как вы пишете код, смогли бы вы мне ответить? Вы занимаетесь написанием кода каждый день, но вы, возможно, даже не задумывались над тем, как именно вы пишете этот код. Если вы не можете объяснить, что вы делаете, как вы можете понять, для чего используется объектно-ориентированное программирование?

Поэтому давайте для начала определимся с тем, какой стиль кодирования (парадигму программирования) вы используете.

Паради́гма программи́рования — это совокупность идей и понятий, определяющих стиль написания компьютерных программ (подход к программированию). Это способ концептуализации, определяющий организацию вычислений и структурирование работы, выполняемой компьютером.

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

Стиль кодирования? Да. Объектно-ориентированное программирование – это стиль кодирования, а не просто использование классов в вашем коде. Представление о том, что ООП — это использование классов, в корне неверно и вызывает массу проблем для вас и для других людей.

Вы кодируете в процедурном стиле

Процедурное программирование – один из многочисленных существующих стилей программирования. Он относится к более широкому семейству структурного программирования. Объектно-ориентированное программирование также принадлежит к нему. Именно поэтому эти два типа имеют много общих черт.

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

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

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

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

Давайте вернемся к процедурному программированию. Идея его использования является очень простой. Вы организуете свой код при помощи серии упорядоченных шагов. Эти шаги могут быть условными, заключающимися в использовании if-операторов или switch, к примеру. Выполнение этих упорядоченных шагов зависит от того, как именно вы хотите получить результат.

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

Это не самый плохой способ программирования. Иногда он является лучшим решением проблемы. В темах использование процедурного кода вполне оправдано. Вы выполняете определенные шаги, выводящие HTML.

Использование процедурного программирования

Давайте взглянем на следующий WordPress-код. Ваша цель состоит в получении списка всех пользователей, которые являются авторами, зарегистрированными после определенной даты. Вы видите шаги, сделанные для получения этого списка.

/**
 * Get all the authors registered after the given date.
 *
 * @param string  $date
 * @param integer $number
 *
 * @return array
 */
function get_authors_registered_after($date, $number = 5)
{
    $results = array();
    $authors = get_users('who=authors&orderby=registered&order=desc');
 
    foreach ($authors as $author) {
        if ($author->user_registered > $date) {
            $results[] = $author;
        }
 
        if (count($results) >= $number) {
            break;
        }
    }
 
    return $results;
}

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

/**
 * Get all the authors registered after the given date.
 *
 * @param string  $date
 * @param integer $number
 *
 * @return array
 */
function get_authors_registered_after($date, $number = 5)
{
    $results = array();
    $query = new WP_User_Query(array(
        'who'     => 'authors',
        'orderby' => 'registered',
        'order'   => 'desc'
    ));
 
    foreach ($query->results as $author) {
        if ($author->user_registered > $date) {
            $results[] = $author;
        }
 
        if (count($results) >= $number) {
            break;
        }
    }
 
    return $results;
}

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

Теперь давайте рассмотрим следующий пример.

class Authors 
{
    /**
     * Get all the authors registered after the given date.
     *
     * @param string  $date
     * @param integer $number
     *
     * @return array
     */
    public function get_registered_after($date, $number = 5)
    {
        $results = array();
        $query = new WP_User_Query(array(
            'who'     => 'authors',
            'orderby' => 'registered',
            'order'   => 'desc'
        ));
 
        foreach ($query->results as $author) {
            if ($author->user_registered > $date) {
                $results[] = $author;
            }
 
            if (count($results) >= $number) {
                break;
            }
        }
 
        return $results;
    }
}

Подождите, ведь это не объектно-ориентированный код? Да, это не ООП. Обертывание вашего кода в класс не меняет вашего пути решения проблемы. Вы по-прежнему совершаете те же самые шаги для получения вашего результата.

Избавляемся от имеющихся ограничений

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

Вы начинаете сталкиваться со сложностями роста. Это происходит по той причине, что у процедурного программирования имеются свои ограничения. Давайте поговорим о некоторых проблемах, с которыми вы можете столкнуться.

Сложности с организацией вашего кода

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

«Куда поместить эту функцию?», спрашиваете вы себя.

Вы создаете отдельный PHP-файл для ее хранения. Когда именно вы должны разбивать тот первый файл на небольшие файлы? Как вы должны назвать эти файлы? Появляется бесконечный список вопросов.

Структурное программирование позволяет вам внести ясность в вашу организацию кода. Если у вас имеются только функции с шагами, все строится на одном и том же фундаменте. Различия между типами функций сглаживаются. Это делает организацию вашего кода сложной в управлении.

Если вы работаете с командой людей, умножьте все эти проблемы в 10 раз.

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

Ваш код прекрасно организован. Клиент обращается к вам с новым проектом. Вы хотите снова использовать некоторую функциональность вашего плагина в этом проекте.

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

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

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

Некоторые проблемы сложно разбить на шаги

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

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

«Как все сложно», размышляете вы, глядя на свою функцию.

Когда появляется ошибка, вы изо всех сил пытаетесь понять, что именно ее вызвало. «Какие условия или группа условий привели к багу?»

Когда проблемы становятся более сложными, вы уже не сможете разбить их на шаги. Ладно, вы можете это сделать, но это будет очень длительным и непростым процессом.

Как объектно-ориентированное программирование позволяет справиться с проблемами

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

Другой важный элемент ООП – общие возможности этих решений. Однако рассмотрение этих возможностей заслуживает отдельной статьи. Пример, представленный далее, продемонстрирует некоторые из них.

Все это приводит нас к использованию классов в ООП. Стоит отметить, что их использование является обманчивым. Классы позволяют реализовать важные возможности, которые определяют ООП, однако они не являются обязательными. Вы можете применить ООП-решения даже без использования классов.

Пример использования паттерна посредника (mediator)

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

Такая зависимость между классами называется сцеплением. Объектно-ориентированное программирование всегда стремится создать минимальное количество сцеплений между классами. Паттерн посредника – одно из решений данной проблемы.

Интерпретация паттерна в WordPress

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

/**
 * Hooks a function or method to a specific filter action.
 */
function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
    global $wp_filter, $merged_filters;
 
    $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
    $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
    unset( $merged_filters[ $tag ] );
    return true;
}
 
/**
 * Call the functions added to a filter hook.
 */
function apply_filters( $tag, $value ) {
    global $wp_filter, $merged_filters, $wp_current_filter;
 
    $args = array();
 
    // Do 'all' actions first
    if ( isset($wp_filter['all']) ) {
        $wp_current_filter[] = $tag;
        $args = func_get_args();
        _wp_call_all_hook($args);
    }
 
    if ( !isset($wp_filter[$tag]) ) {
        if ( isset($wp_filter['all']) )
            array_pop($wp_current_filter);
        return $value;
    }
 
    if ( !isset($wp_filter['all']) )
        $wp_current_filter[] = $tag;
 
    // Sort
    if ( !isset( $merged_filters[ $tag ] ) ) {
        ksort($wp_filter[$tag]);
        $merged_filters[ $tag ] = true;
    }
 
    reset( $wp_filter[ $tag ] );
 
    if ( empty($args) )
        $args = func_get_args();
 
    do {
        foreach( (array) current($wp_filter[$tag]) as $the_ )
            if ( !is_null($the_['function']) ){
                $args[1] = $value;
                $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
            }
 
    } while ( next($wp_filter[$tag]) !== false );
 
    array_pop( $wp_current_filter );
 
    return $value;
}

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

Почему это ООП

Первое, что вы, возможно, отметили для себя – то, что здесь нет никаких используемых объектов. Однако, даже учитывая тот факт, что здесь нет объектов, это по-прежнему объектно-ориентированное программирование. Это отсылает нас к тем возможностям, которые уже были упомянуты ранее. Реализация WordPress имеет некоторые возможности, которые должно иметь объектно-ориентированное решение.

Код плагинов отделен от внутренних функций WordPress. Мантра «не ломайте ядро» отражает важность такого отделения. Система хуков и фильтров – краеугольный камень этой идеи.

Функции фильтров также содержат внутренний список хуков, что реализовано при помощи глобальной переменной $wp_filter. Объектно-ориентированное решение всегда хранит внутреннюю информацию. Эта идея является частью более крупной особенности, называемой инкапсуляцией. Инкапсуляция позволяет вам сохранить ваш код модульным и простым.

Слабые места интерпретации Wordpress

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

Использование глобальных переменных также ограничивает повторное использование кода. Вы можете копировать и вставлять код в другой PHP-проект. Однако вы не можете использовать решение в языке программирования, который не использует глобальные переменные тем же самым путем.

Это не является универсальным решением проблемы.

Если бы это имело вид класса

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

class WP_Filters
{
    protected $filters = array();
 
    /**
     * Hooks a function or method to a specific filter action.
     *
     * @param string  $tag
     * @param mixed   $function
     * @param integer $priority
     * @param integer $accepted_args
     */
    public function add($tag, $function, $priority = 10, $accepted_args = 1)
    {
    }
 
    /**
     * Call the functions added to a filter hook.
     *
     * @param string $tag
     * @param mixed $value
     */
    public function apply($tag, $value)
    {
    }
 
    /**
     * Remove all of the hooks from a filter.
     * 
     * @param string  $tag
     */
    public function clear($tag)
    {
    }
 
    /**
     * Removes a function from a specified filter hook.
     *
     * @param string  $tag
     * @param mixed   $function
     * @param integer $priority
     */
    public function remove($tag, $function, $priority = 10)
    {
    }
 
    /**
     * Build Unique ID for storage and retrieval.
     *
     * @param string  $tag
     * @param mixed   $function
     * @param integer $priority
     */
    protected function build_unique_id($tag, $function, $priority)
    {
    }
}

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

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

ООП позволяет решить более сложные проблемы

Пример, представленный выше, является простым, однако он позволяет решить все проблемы, отмеченные ранее. Вы смогли бы:

  • организовать свой код так, чтобы эффективно решить проблему;
  • упростить повторное использование кода;
  • справиться с комплексными проблемами без написания грязного кода.

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

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

Источник: https://carlalexander.ca

Поделиться

16 комментариев

  1. «Ваши хуки теперь не могут быть взломаны» Ну то есть к ним нельзя будет прицепиться не создав объект класса WP_Filters который создать не сложно, но каждый раз не хотелось бы это делать. От чего это защитить должно как то не понятно, зато можно сделать хуки к которым сложно цепляться или в чем идея была ? Кто понял объясните.

    • Дмитрий says:

      Видимо, здесь имеется в виду то, что к ним сложно подцепиться. И это хоть как-то, да защищает от сторонних подцеплений.

  2. 0p says:

    объектно-ориентированное программирование нужно не только для вордпресс, если осваивать любую CMS более досканально рано или поздно придешь к необходимости применять ООП.

    • event says:

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

  3. Мне кажется начинать в данной области необходимо с 0ля. Тогда человек будет иметь полной понятие и давать отчетность своим действиям.

  4. Волшебник says:

    Дмитрий, а как у вас с ООП?

    • Дмитрий says:

      Не то чтобы очень. Знания еще с университета имеются, но базовые и применительно к C++.

  5. Волшебник says:

    А я так и не взялся его изучать, т.к. сложно и не нужно. Базовые понятия поверхностно знаю, но не применял, т.к. для повседневных нужд хватает обычного php.

    Возможно он может быть полезен для тех, кто пишет очень сложный и объемный код типа CMS и т.п.

    • Дмитрий says:

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

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

    • Дмитрий says:

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

      Кого-то может это и отпугнет, но если человек настойчивый, то своего добьется.

  7. Олег says:

    Считаю не стоит заморачиваться с ООП, конечно для опыта и самообразования желательно, в веб-программирование нет таких сложных витееватых кодов как например в С# или Delphi

    • Да ладно , нет а если у меня скажем там система которая скажем работает с таймдифами или в одно поле кучу инфы серилизовать )) На функциях я это как сделаю ? Там же черт ногу сломит )) опять же постранства имён в голове удержать весьма не просто если пишеш что то больше хелоу ворда )). Вобщем нет ооп использовать необходимо и это мало общего имеет с прости господи Делфи там оно несколько иначе реализуется

  8. Олег says:

    Поэтому ООП невозможно реализовать в веб-программирование, нет тех средств

    • Да ладно ?

      А это про что пишут
      http://php.net/manual/ru/language.oop5.changelog.php
      http://www.php.su/learnphp/phpoo/?basic

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

      В вебе и java и .NET используется)) каких тех средств нет ?

      • и это все только то что касается поддержки языками программирования, а вобще ООП это парадигма, как её реализовывать личное дело каждого, речь не об языках по сути

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.