WordPress как на ладони
Очень Удобный и Быстрый Хостинг для сайтов на WordPress. Пользуюсь сам и вам рекомендую!

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

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

Ищем WP-разработчика! Фулл-тайм, удаленка, хорошая зарплата, соц. пакет. Подробности.
Компания Boosta.

Суть проблемы.

Фильтр в 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

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

Вариант 1

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

// функция для фильтра
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', [ $str, $num ] );

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

Передача объекта в фильтр или событие по ссылке

Объекты всегда передаются по ссылке. Поэтому если в фильтре мы указываем объект, то не обязательно что-то придумывать, можно использовать стандартные функции хуков: apply_actions() или apply_filters().

class MyClass {

	public $var;

	function __construct(){
		$this->var = 'Привет';
	}

}

add_filter( 'myfilter', function( $MyClass ){
	$MyClass->var .= ' Мир!';

	return $MyClass;
} );

$MyClass = new MyClass();

$MyClass = apply_filters( 'myfilter', $MyClass );

print_r( $MyClass );
/*
MyClass Object (
	[var] => Привет Мир!
)
*/
3 коммента
    Войти