Передача переменных по ссылке в хуках WordPress: решения и примеры

# Передача переменных по ссылке в 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!
)
*/

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *