# Передача переменных по ссылке в apply_filters() и do_action()
В этой заметке мы рассмотрим, как передавать переменные по ссылке в фильтры WordPress. Это нечасто требуется, но иногда может быть необходимо.
## Суть проблемы
Фильтры WordPress изменяют переданное значение: они меняют значение переменной и возвращают его обратно в контекст, из которого был вызван фильтр. Однако это касается только первой переменной, а дополнительные переменные просто передаются фильтру и могут использоваться там для разных целей, но мы не можем изменить их так, чтобы это повлияло на переданную переменную.
Например, в PHP мы можем сделать следующее:
function func( $string, & $number ){
$number = 2;
return $string . ' orange';
}
$num = 1;
$str = 'crazy';
$str = func( $str, $num );
echo $str; //> crazy orange
echo $num; //> 2
Как видно, мы изменили переменную $num
из функции. Это и есть передача переменной по ссылке из текущего контекста в контекст функции.
Но в фильтрах WordPress сделать это нельзя:
// функция для фильтра
function func( $string, & $number ){
$number = 2;
return $string . ' orange';
}
// прикрепление функции к фильтру
add_filter( 'myfilter', 'func', 0, 2 );
// вызов фильтра
$num = 1;
$str = 'crazy';
// оба вызова фильтра приведут к ошибке PHP
$str = apply_filters('myfilter', $str, $num ); //> ошибка: функция ожидает ссылку
$str = apply_filters('myfilter', $str, & $num ); //> ошибка: неожиданный символ &
## Передача переменной по ссылке в фильтрах WordPress
В качестве решения этой проблемы можно использовать глобальную переменную, которая будет видна из любого контекста. Однако это плохое решение, поскольку использование глобальных переменных может повлиять на работу других процессов и привести к конфликтам. Конечно, мы иногда прибегаем к этому при отсутствии других решений.
### Вариант 1
Необходимо передать две переменные в первом параметре фильтра, чтобы мы могли влиять на обе сразу, а не только на первую. Мы можем передать две переменные, поместив их в массив и передав этот массив. Это выглядит так:
// функция для фильтра
function func( $array ){
list( $string, $number ) = $array;
$string = $string . ' orange';
$number = 2;
return array( $string, $number );
}
// прикрепление функции к фильтру
add_filter( 'myfilter', 'func' );
// вызов фильтра
$num = 1;
$str = 'crazy';
list( $str, $num ) = apply_filters( 'myfilter', [ $str, $num ] );
// посмотрим, что у нас получилось
echo $str; //> crazy orange
echo $num; //> 2
### Вариант 2
Текущую проблему можно также решить, используя специальную функцию apply_filters_ref_array()
.
## Передача переменной по ссылке в событиях WordPress
Помимо всего вышеперечисленного, следует добавить, что в событиях WordPress также возможно передавать переменные по ссылке. Для этого существует специальная функция событий do_action_ref_array()
.
// привязываем действие
add_action( 'myhook', 'myhook_func' );
function myhook_func( & $num ){
$num = 2; // изменяем переменную по ссылке
}
$num = 1;
// обработка действия
do_action_ref_array('myhook', array( & $num ));
echo $num; //> 2
В заключение, советую ознакомиться со всеми функциями хуков WordPress.
## Передача объекта по ссылке в фильтр или событие
Объекты всегда передаются по ссылке. Поэтому, если мы укажем объект в фильтре, нет необходимости придумывать что-то особенное, мы можем использовать стандартные функции хуков: do_action()
или apply_filters()
.
class MyClass {
public $var;
function __construct(){
$this->var = 'Hello';
}
}
add_filter( 'myfilter', function( $MyClass ){
$MyClass->var .= ' World!';
return $MyClass;
} );
$MyClass = new MyClass();
$MyClass = apply_filters( 'myfilter', $MyClass );
print_r( $MyClass );
/*
MyClass Object (
[var] => Hello World!
)
*/