Скажем, у меня есть этот PHP-код:
$FooBar = "a string";
Затем мне нужна такая функция:
print_var_name($FooBar);
которая печатает:
FooBar
Любые идеи, как этого добиться? Возможно ли это вообще в PHP?
Ответ 1
Вы можете использовать get_defined_vars(), чтобы определить имя переменной, которая имеет то же значение, что и та, имя которой вы пытаетесь найти. Очевидно, это не всегда будет работать, поскольку разные переменные часто имеют одинаковые значения, но это единственный способ, который я могу придумать для этого.
get_defined_vars() в некоторых ситуациях работает некорректно, она возвращает var, потому что $var используется в самой функции.
function print_var_name($var) {
foreach($GLOBALS as $var_name => $value) {
if ($value === $var) {
return $var_name;
}
}
return false;
}
В PHP нет хорошего способа сделать это, вероятно, потому, что вам не нужно этого делать. Возможно, есть более эффективные способы сделать то, что вы пытаетесь сделать.
Ответ 2
Я не могу уверенно утверждать, как сделать это эффективно, но я придумал вот что. Это работает для ограниченного использования, как указано ниже.
<?php
function varName( $v ) {
$trace = debug_backtrace();
$vLine = file( __FILE__ );
$fLine = $vLine[ $trace[0]['line'] - 1 ];
preg_match( "#\\$(\w+)#", $fLine, $match );
print_r( $match );
}
$foo = "knight";
$bar = array( 1, 2, 3 );
$baz = 12345;
varName( $foo );
varName( $bar );
varName( $baz );
?>
// Результат
Array (
[0] => $foo
[1] => foo
)
Array (
[0] => $bar
[1] => bar
)
Array (
[0] => $baz
[1] => baz
)
Это работает на основе строки, вызывающей функцию, где она находит аргумент, который вы передали. Я полагаю, что его можно было бы расширить для работы с несколькими аргументами, но, если бы вы могли лучше объяснить ситуацию, вероятно, другое решение будет работать лучше.
Ответ 3
Похоже, никто не упомянул основные причины, по которым это а) сложно и б) неразумно:
-
«Переменная» — это просто символ, указывающий на что-то еще. В PHP она внутренне указывает на что-то, называемое «zval», которое на самом деле может использоваться для нескольких переменных одновременно либо потому, что они имеют одинаковое значение (PHP реализует то, что называется «копирование при записи», поэтому для $foo = $bar нет необходимости выделить дополнительную память сразу), либо потому, что они были назначены (или переданы функции) по ссылке (например, $foo =& $bar).
-
Когда вы передаете параметр функции, вы создаете новую переменную (даже если это ссылка). Вы можете передать что-то анонимное, например, "hello", но, оказавшись внутри вашей функции, это будет та переменная, как вы ее назовете. Это довольно фундаментально для разделения кода: если бы функция полагалась на то, как называлась переменная, она была бы больше похожа на goto, чем отдельную функцию.
-
Глобальные переменные обычно считаются плохой идеей. Многие примеры здесь предполагают, что переменная, которую вы хотите «отразить», может быть найдена в $GLOBALS, но это будет верно только в том случае, если вы плохо структурировали свой код и переменные не привязаны к какой-либо функции или объекту.
-
Имена переменных помогают программистам читать свой код. Переименование переменных в соответствии с их назначением — очень распространенная практика рефакторинга, и все дело в том, что это не имеет никакого значения.
Теперь я понимаю желание использовать это для отладки (хотя некоторые из предложенных вариантов использования выходят далеко за рамки этого), но как обобщенное решение это не так полезно, как можно подумать: если ваша функция отладки говорит, что ваша переменная называется "$file", это может быть любая из десятков переменных "$file" в вашем коде, или переменная, которую вы назвали "$filename", но передаете в функцию, параметр которой называется "$file".
Гораздо более полезной информацией является то, откуда в вашем коде была вызвана функция отладки. Поскольку вы можете быстро найти это в редакторе, вы можете увидеть, какую переменную вы выводили, и даже передать в нее целые выражения за один раз (например, debug('$foo + $bar = ' . ($foo + $bar))).
Для этого вы можете использовать этот фрагмент в верхней части вашей функции отладки:
$backtrace = debug_backtrace();
echo '# Debug function called from ' . $backtrace[0]['file'] . ' at line ' . $backtrace[0]['line'];
Ответ 4
Это именно то, что вам нужно,— готовая к использованию функция "скопируй и вставь", которая определяет имя заданной переменной:
function print_var_name() {
// читаем обратную трассировку
$bt = debug_backtrace();
// читаем файл
$file = file($bt[0]['file']);
// выбираем точную строку print_var_name($varname)
$src = $file[$bt[0]['line']-1];
// шаблон поиска
$pat = '#(.*)'.__FUNCTION__.' *?\( *?(.*) *?\)(.*)#i';
// извлечение $varname из совпадения №2
$var = preg_replace($pat, '$2', $src);
// выводим в браузер
echo '<pre>' . trim($var) . ' = ' . print_r(current(func_get_args()), true) . '</pre>';
}