При разработки масштабируемых приложений часто применяют хуки в PHP. Кому-то хуки нравятся, кому-то нет, но так или иначе с ними приходится иметь дело и проблема в том, что не все понимают, как это работает.
В данной статье я расскажу принцип — как работают хуки в PHP. Использовать хуки можно в любом веб-приложении, например тот, кто работает с WordPress постоянно с ними сталкивается. Использование хуков дает гибкость приложению и позволяет сторонним разработчикам расширять функционал без вмешательства в основной код.
Рассмотрим простой пример
Есть HTML шаблон и он уже заверстан. Предположим, что по каким-то причинам нельзя вмешиваться в код шаблона и что-либо менять, но при этом есть необходимость дополнить его данными.
Чаще всего возникает необходимость дополнить HTML шаблон мета-тегами, стилями, скриптами в шапке или в подвале.
Пусть существует следующий шаблон страницы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!doctype html> <html lang="ru"> <head> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- Мета теги, стили, скрипты --> </head> <body> <!-- Основной контент --> <!-- Скрипты --> </body> </html> |
Чтобы дать возможность добавлять мета-теги, стили и скрипты, разработчику необходимо снабдить шаблон хуками и добавить функции обработки. По сути, хуки — это крючки, за которые можно зацепиться, то есть идентифицировать то место, в котором необходимо произвести какое-либо дополнительное действие.
Код приобретет следующий вид:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!doctype html> <html lang="ru"> <head> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <?php do_action('header'); ?> </head> <body> <!-- Основной контент --> <?php do_action('footer'); ?> </body> </html> |
Далее рассмотрим, что из себя представляет функция do_action
.
Как do_action узнает какие функции нужно выполнить
В действительности все названия функций, которые должны быть выполнены на определенном хуке хранятся в массиве. Переменная, содержащая этот массив, является глобальной и доступна во всем приложении, следовательно мы можем дописывать данные в эту переменную.
Пусть массив имеет следующий вид:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Array( hook_name_1 => Array( index_1_1 => function_name_1_1, index_1_2 => function_name_1_2, .. index_1_n => function_name_1_n, ), .. hook_name_m => Array( index_m_1 => function_name_m_1, index_m_2 => function_name_m_2, .. index_m_k => function_name_m_k, ), ) |
Получается, что есть списки, которые складываются в один большой список, где hook_name_x
— это название какого-то хука, index_x_x
— индекс(порядковый номер) функции function_name_x_x
в списке указанного хука.
При этом порядковый номер функции в списке можно использовать для определения последовательности выполнения функций — чем больше значение индекса, тем ниже эта функция будет в списке, а значит тем позже она будет выполнена.
Все это можно объяснить на примере: представьте себе человека, который спускается на лифте и у него в руках тетрадь, каждая страница которой соответствует какому-либо этажу, на котором останавливается лифт, на каждой странице имеется список задач, которые следует выполнить на соответствующем этаже. В данном примере названия этажей являются хуками, а элементы списка(задачи) на каждой странице, являются функциями, привязанными к конкретному хуку. Очередность выполнения задач определяется их положением в списке, сверху вниз.
Привязка функции к хуку
Для того, чтобы указать по какому хуку следует выполнить функцию, необходимо добавить название функции в соответствующий список. При этом должна быть возможность указать приоритет выполнения функции.
1 2 3 4 5 6 7 | function add_action( $tag, $callback, $priority = 10 ) { global $hooks; $priority = find_next_priority( $tag, $priority ); $hooks[ $tag ][ $priority ] = $callback; ksort( $hooks[ $tag ], SORT_NUMERIC ); } |
$tag
— имя хука, $callback
— название функции, которая будет выполнена по данному хуку, $priority
— приоритет выполнения, с указанным значением по умолчанию.
Внутри функции говорится, что необходимо переменную $hooks
воспринимать, как глобальную. Следующим шагом будет нахождение не занятого индекса в списке функций, привязанных к указанному хуку, по средствам функции find_next_priority
. После того, как не занятый индекс найден, функция добавляется в список под найденным индексом. Список сортируется в соответствии с порядковым номером — индексом.
Выполнение функций по хуку
Поскольку в PHP выполнение программы последовательное, обработчик будет добираться до каждого хука по мере его нахождения, как только хук будет найден, будут выполнены все функции, которые есть в соответствующем списке.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function do_action( $name ) { global $hooks; // если в списке присутствует указанный хук if ( ! empty( $hooks[ $name ] ) ) { // перебор названий функций в списке данного хука foreach ( $hooks[ $name ] as $function_name ) { // если указанная функция существует if ( function_exists( $function_name ) ) { // она выполняется $function_name(); } } } } |
Добавление хуков внутри приложения происходило путем простановки функций do_action( $name )
в нужных местах шаблона, где $name
— это имя конкретного хука.
Если функция, найденная в списке указанного хука существует, она выполняется.
Хуки в PHP — итог
Таким образом, если в приложении расставлены хуки, можно выполнять какие-либо действия, например вывод данных, без необходимости редактирования основного кода.
Это позволит расширить функционал приложения, не нанеся ему вред. По такому принципу работают, например, плагины в WordPress, они расширяют функционал, без фактического изменения кода системы.
Приведенный пример является упрощенной моделью системы хуков, описывающий принцип их работы.
По данной теме я провел вебинар, который может быть полезен:
Ссылка на исходники: php-hooks.zip
Данный вебинар на GeekBrains: Хуки в приложении на PHP