WordPress как на ладони
wordpress jino

Передача переменных по ссылке в apply_filters

Эта никому ненужная заметка, повествует о том как передать в фильтр переменную по ссылке. Такое бывает нужно крайне редко, но когда нужно и от этого не уйти, то это может стать проблемой. А проблемы подобного рода решаются в программировании как? Правильно! Костылями. Но! В этой заметке я обойдусь без них, во всяком случая я надеюсь, что это так.

Итак, суть проблемы...

Фильтр в WordPress изменяет передаваемое значение: изменяет значение переданной переменной и возвращает его в контекст, откуда был вызван фильтр. Но делает он это только с первой переменной, а остальные, дополнительные переменные просто передаются в фильтр и могут быть там использованы для всяких целей, но изменить их, так чтобы изменение повлияло на ту переменную которая передавалась мы никак не можем.

Например в PHP мы можем сделать так:

function func( $string, & $number ){
	$number = 2;
	return $string . ' апельсин';
}

$num = 1;
$str = 'сумасшедший';

$str = func( $str, $num ); 

echo $str; //> сумасшедший апельсин
echo $num; //> 2 

Как видно, мы повлияли на переменную $num из функции... Это и есть передача переменной по ссылке из текущего контекста в контекст функции.

Но в фильтрах WordPress мы так не можем:

// функция для фильтра
function func( $string, & $number ){
	$number = 2;
	return $string . ' апельсин';
}

// подключаем функцию к фильтру
add_filter('myfilter', 'func', 0, 2 );

// вызываем фильтр
$num = 1;
$str = 'сумасшедший';

// оба вызова фильтра завершатся ошибкой PHP
$str = apply_filters('myfilter', $str, $num ); //> ошибка: функция ждет ссылку
$str = apply_filters('myfilter', $str, & $num ); //> ошибка: неожиданный символ & 

Передача переменной по ссылке в фильтрах WordPress

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

Правильный способ

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

// функция для фильтра
function func( $array ){
	list( $string, $number ) = $array;

	$string = $string . ' апельсин';
	$number = 2;

	return array( $string, $number );
}

// подключаем функцию к фильтру
add_filter('myfilter', 'func' );

// вызываем фильтр
$num = 1;
$str = 'сумасшедший';

list( $str, $num ) = apply_filters('myfilter', array( $str, $num ) );

// смотрим что получилось
echo $str; //> сумасшедший апельсин
echo $num; //> 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.

2 коммента
  • campusboy2857 cайт: www.youtube.com/c/wpplus

    Возможно скажу глупость, но использование статических переменных не решит проблему?

    Ответить2 года назад #
    • Kama5409

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

      Ответить2 года назад #
Здравствуйте, !     Войти . Зарегистрироваться