Гипотетический пример, но применимость в реальном мире (для тех, кто учится, как я).
Учитывая этот код:
<?php
function send_money_to_grandma() {
internetofThings("send grandma","$1");
}
add_action('init','send_money_to_grandma');
add_action('init','send_money_to_grandma');
Хорошо, теперь я поднимаю свой WP сайт и захожу. Я просматриваю несколько страниц в Admin. Действие 'init' срабатывает в общей сложности 100 раз, прежде чем аккумулятор моего ноутбука разрядится.
Первые вопросы: сколько денег мы отправили бабушке? Это 1, 2, 100 или 200 (или что-то еще?)
Если бы вы могли также объяснить свой ответ, это было бы здорово.
Вторые вопросы: если мы хотим убедиться, что отправляем только бабушке 1 доллар, как лучше это сделать? Глобальная переменная (семафор), которая получает значение 'true' при первой отправке $ 1? Или есть какой-то другой тест, чтобы увидеть, произошло ли какое-либо действие уже и предотвратить его многократное срабатывание?
Третий вопрос: это то, что беспокоит разработчиков плагинов? Я понимаю, что мой пример глуп, но я думал как о проблемах производительности, так и о других неожиданных побочных эффектах (например, если функция обновляется / вставляется в базу данных).
Ответы:
Вот несколько случайных мыслей по этому поводу:
Вопрос 1
Для загрузки 100 страниц мы отправили ей 100 x 1 = 100 $.
Здесь мы на самом деле имеем в виду
100 x do_action( 'init' )
звонки.Неважно, что мы добавили его дважды:
потому что обратные вызовы и приоритеты (по умолчанию 10) идентичны .
Мы можем проверить, что
add_action
это просто оболочка дляadd_filter
этого, который создает глобальный$wp_filter
массив:Однако если мы изменили приоритет:
тогда мы отправим ей 2 х 1 долл. за загрузку страницы или 200 долл. за загрузку 100 страниц.
То же самое, если обратные вызовы, где разные:
Вопрос 2
Если мы хотим отправить его только один раз на страницу загрузки , то это должно быть сделано:
потому что
init
крюк срабатывает только один раз. У нас могут быть другие хуки, которые запускаются много раз за загрузку страницы.Давай позвоним:
но что произойдет, если
someaction
срабатывает 10 раз за загрузку страницы?Мы могли бы настроить
send_money_to_grandma()
функцию сили используйте статическую переменную в качестве счетчика:
Если мы хотим запустить его только один раз (когда-либо!), Мы можем зарегистрировать параметр в
wp_options
таблице через API параметров :Если мы хотим отправлять ей деньги раз в день, тогда мы можем использовать Transient API
или даже использовать wp-cron.
Обратите внимание, что у вас могут быть вызовы ajax. также.
Есть способы проверить это, например, с
DOING_AJAX
Также могут быть перенаправления, которые могут прервать поток.
Тогда мы могли бы ограничить только на внутренний интерфейс
is_admin()
или нет:! is_admin()
.Вопрос № 3
да это важно
Если мы хотим сделать нашу бабушку очень счастливой, мы бы сделали:
но это было бы очень плохо для производительности ... и наш кошелек ;-)
источник
Это скорее комментарий к очень хорошему ответу Биргире, чем полный ответ, но из-за необходимости писать код комментарии не подходят.
Из ответа может показаться, что единственной причиной, по которой действие добавляется один раз в пример кода OP, даже если он
add_action()
вызывается дважды, является тот факт, что используется один и тот же приоритет. Это не правда.В коде
add_filter
важной части есть_wp_filter_build_unique_id()
вызов функции, который создает уникальный идентификатор для каждого обратного вызова .Если вы используете простую переменную, например строку, содержащую имя функции, например
"send_money_to_grandma"
, тогда идентификатор будет равен самой строке, поэтому, если приоритет одинаков, то же самое с идентификатором, обратный вызов добавляется один раз.Однако не все так просто. Обратные вызовы могут быть чем угодно, что есть
callable
в PHP:Первые два представлены соответственно строкой и массивом из 2 строк (
'send_money_to_grandma'
иarray('MoneySender', 'send_to_grandma')
), поэтому идентификатор всегда одинаков, и вы можете быть уверены, что обратный вызов добавляется один раз, если приоритет одинаков.Во всех остальных 3 случаях идентификатор зависит от экземпляров объекта (анонимная функция является объектом в PHP), поэтому обратный вызов добавляется один раз, только если объект является одним и тем же экземпляром , и важно отметить, что тот же экземпляр и тот же класс это две разные вещи.
Возьмите этот пример:
Сколько долларов мы отправляем за загрузку страницы?
Ответ 2, потому что идентификатор WordPress генерирует для
$sender1
и$sender2
разные.То же самое происходит в этом случае:
Выше я использовал функцию
sent_to_grandma
внутри замыканий, и даже если код идентичен, 2 замыкания - это 2 разных экземпляра\Closure
объекта, поэтому WP создаст 2 разных идентификатора, в результате чего действие будет добавлено дважды, даже если приоритет одинаков.источник
Вы не можете добавить одно и то же действие к тому же хуку действий с тем же приоритетом .
Это сделано для того, чтобы несколько плагинов, полагающихся на действие сторонних плагинов, происходили более одного раза (например, woocommerce и все его сторонние плагины, такие как интеграция шлюзов и т. Д.). Поэтому без указания приоритета бабушка остается бедной:
Однако, если вы добавите приоритет к этим действиям:
Бабушка теперь умирает с 4 долларами в кармане (1, 2, 3 и по умолчанию: 10).
источник