Как получить имя переменной как строку в PHP?

Скажем, у меня есть этот код PHP:

$FooBar = "a string"; 

Мне нужна такая функция:

 print_var_name($FooBar); 

который печатает:

 FooBar 

Любые идеи, как достичь этого? Возможно ли это в PHP?

Вы можете использовать get_defined_vars (), чтобы найти имя переменной, которая имеет то же значение, что и имя, которое вы пытаетесь найти. Очевидно, что это не всегда будет работать, поскольку разные переменные часто имеют одинаковые значения, но это единственный способ, которым я могу это сделать.

Изменить: get_defined_vars () работает некорректно, он возвращает 'var', потому что $ $ используется в самой функции. $ GLOBALS, похоже, работает, поэтому я изменил его на это.

 function print_var_name($var) { foreach($GLOBALS as $var_name => $value) { if ($value === $var) { return $var_name; } } return false; } 

Изменить: чтобы быть ясным, в PHP нет хорошего способа сделать это, вероятно, потому, что вам не нужно это делать. Вероятно, есть лучшие способы сделать то, что вы пытаетесь сделать.

Я не мог придумать способ сделать это эффективно, но я придумал это. Он работает для ограниченного использования ниже.

пожимание плечами

 <?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 ); ?> // Returns Array ( [0] => $foo [1] => foo ) Array ( [0] => $bar [1] => bar ) Array ( [0] => $baz [1] => baz ) 

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

Вы можете подумать об изменении своего подхода и использовании имени переменной переменной?

 $var_name = "FooBar"; $$var_name = "a string"; 

то вы могли бы просто

 print($var_name); 

получить

 FooBar 

Вот ссылка на руководство PHP по переменным переменным

Никто, кажется, не упомянул о фундаментальных причинах, почему это: а) жесткий и б) неразумный:

  • «Переменная» – это просто символ, указывающий на что-то другое. В PHP он внутренне указывает на то, что называется «zval», которое фактически может использоваться для нескольких переменных одновременно, либо потому, что они имеют одинаковое значение (PHP реализует нечто, называемое «copy-on-write», так что $foo = $bar не нужно выделять лишнюю память) или потому, что они были назначены (или переданы функции) по ссылке (например, $foo =& $bar ). Так что у zval нет имени.
  • Когда вы передаете параметр функции, вы создаете новую переменную (даже если это ссылка). Вы могли бы передать что-то анонимное, например "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']; 

Я сделал функцию проверки для отладки. Это похоже на print_r () на стероиды, подобно Krumo, но немного эффективнее на объектах. Я хотел добавить обнаружение имени var и вышел с этим, вдохновленный сообщением Ника Престы на этой странице. Он обнаруживает любое выражение, переданное как аргумент, а не только имена переменных.

Это только функция-обертка, которая обнаруживает переданное выражение. Работает в большинстве случаев. Он не будет работать, если вы вызовете функцию более одного раза в одной строке кода.

Это отлично работает: die ( проверка ( $ this-> getUser () -> hasCredential ("delete") ) );

inspect () – это функция, которая будет обнаруживать переданное выражение.

Мы получаем: $ this-> getUser () -> hasCredential ("delete")

 function inspect($label, $value = "__undefin_e_d__") { if($value == "__undefin_e_d__") { /* The first argument is not the label but the variable to inspect itself, so we need a label. Let's try to find out it's name by peeking at the source code. */ /* The reason for using an exotic string like "__undefin_e_d__" instead of NULL here is that inspected variables can also be NULL and I want to inspect them anyway. */ $value = $label; $bt = debug_backtrace(); $src = file($bt[0]["file"]); $line = $src[ $bt[0]['line'] - 1 ]; // let's match the function call and the last closing bracket preg_match( "#inspect\((.+)\)#", $line, $match ); /* let's count brackets to see how many of them actually belongs to the var name Eg: die(inspect($this->getUser()->hasCredential("delete"))); We want: $this->getUser()->hasCredential("delete") */ $max = strlen($match[1]); $varname = ""; $c = 0; for($i = 0; $i < $max; $i++){ if( $match[1]{$i} == "(" ) $c++; elseif( $match[1]{$i} == ")" ) $c--; if($c < 0) break; $varname .= $match[1]{$i}; } $label = $varname; } // $label now holds the name of the passed variable ($ included) // Eg: inspect($hello) // => $label = "$hello" // or the whole expression evaluated // Eg: inspect($this->getUser()->hasCredential("delete")) // => $label = "$this->getUser()->hasCredential(\"delete\")" // now the actual function call to the inspector method, // passing the var name as the label: // return dInspect::dump($label, $val); // UPDATE: I commented this line because people got confused about // the dInspect class, wich has nothing to do with the issue here. echo("The label is: ".$label); echo("The value is: ".$value); } 

Ниже приведен пример функции инспектора (и моего класса dInspect):

http://inspect.ip1.cc

Тексты на испанском языке на этой странице, но код является кратким и очень простым для понимания.

Lucas на PHP.net предоставил надежный способ проверить, существует ли переменная. В его примере он выполняет итерацию с помощью копии массива глобальных переменных (или массива с ограниченным диапазоном) переменных, изменяет значение на случайно генерируемое значение и проверяет генерируемое значение в скопированном массиве.

 function variable_name( &$var, $scope=false, $prefix='UNIQUE', $suffix='VARIABLE' ){ if($scope) { $vals = $scope; } else { $vals = $GLOBALS; } $old = $var; $var = $new = $prefix.rand().$suffix; $vname = FALSE; foreach($vals as $key => $val) { if($val === $new) $vname = $key; } $var = $old; return $vname; } 

Затем попробуйте:

 $a = 'asdf'; $b = 'asdf'; $c = FALSE; $d = FALSE; echo variable_name($a); // a echo variable_name($b); // b echo variable_name($c); // c echo variable_name($d); // d 

Обязательно проверьте свой пост на PHP.net: http://php.net/manual/en/language.variables.php

Многие ответы ставят под сомнение полезность этого. Однако получение ссылки на переменную может быть очень полезным. Особенно в случаях с объектами и $ this . Мое решение работает с объектами, а также как объекты, определенные свойствами:

 function getReference(&$var) { if(is_object($var)) $var->___uniqid = uniqid(); else $var = serialize($var); $name = getReference_traverse($var,$GLOBALS); if(is_object($var)) unset($var->___uniqid); else $var = unserialize($var); return "\${$name}"; } function getReference_traverse(&$var,$arr) { if($name = array_search($var,$arr,true)) return "{$name}"; foreach($arr as $key=>$value) if(is_object($value)) if($name = getReference_traverse($var,get_object_vars($value))) return "{$key}->{$name}"; } с function getReference(&$var) { if(is_object($var)) $var->___uniqid = uniqid(); else $var = serialize($var); $name = getReference_traverse($var,$GLOBALS); if(is_object($var)) unset($var->___uniqid); else $var = unserialize($var); return "\${$name}"; } function getReference_traverse(&$var,$arr) { if($name = array_search($var,$arr,true)) return "{$name}"; foreach($arr as $key=>$value) if(is_object($value)) if($name = getReference_traverse($var,get_object_vars($value))) return "{$key}->{$name}"; } 

Пример для вышеизложенного:

 class A { public function whatIs() { echo getReference($this); } } $B = 12; $C = 12; $D = new A; echo getReference($B)."<br/>"; //$B echo getReference($C)."<br/>"; //$C $D->whatIs(); //$D 

От php.net

@Alexandre – короткое решение

 <?php function vname(&$var, $scope=0) { $old = $var; if (($key = array_search($var = 'unique'.rand().'value', !$scope ? $GLOBALS : $scope)) && $var = $old) return $key; } ?> 

@Lucas – использование

 <?php //1. Use of a variable contained in the global scope (default): $my_global_variable = "My global string."; echo vname($my_global_variable); // Outputs: my_global_variable //2. Use of a local variable: function my_local_func() { $my_local_variable = "My local string."; return vname($my_local_variable, get_defined_vars()); } echo my_local_func(); // Outputs: my_local_variable //3. Use of an object property: class myclass { public function __constructor() { $this->my_object_property = "My object property string."; } } $obj = new myclass; echo vname($obj->my_object_property, $obj); // Outputs: my_object_property ?> 

Это именно то, что вы хотите – его готовая к использованию функция «копировать и вбрасывать», которая возвращает имя данного var:

 function print_var_name(){ // read backtrace $bt = debug_backtrace(); // read file $file = file($bt[0]['file']); // select exact debug($varname) line $src = $file[$bt[0]['line']-1]; // search pattern $pat = '#(.*)print_var_name *?\( *?\$(.*) *?\)(.*)#i'; // extract $varname from match no 2 $var = preg_replace($pat, '$2', $src); // print to browser echo trim($var); } 

ИСПОЛЬЗОВАНИЕ: print_var_name ($ FooBar)

ПЕЧАТЬ: FooBar

СОВЕТ Это не доказательство пули: если функция вызывается более одного раза (в одной строке), она не сработает!

Адаптированный из ответов выше для многих переменных, с хорошей производительностью, всего лишь одно сканирование GLOBALS для многих

 function compact_assoc(&$v1='__undefined__', &$v2='__undefined__',&$v3='__undefined__',&$v4='__undefined__',&$v5='__undefined__',&$v6='__undefined__',&$v7='__undefined__',&$v8='__undefined__',&$v9='__undefined__',&$v10='__undefined__',&$v11='__undefined__',&$v12='__undefined__',&$v13='__undefined__',&$v14='__undefined__',&$v15='__undefined__',&$v16='__undefined__',&$v17='__undefined__',&$v18='__undefined__',&$v19='__undefined__' ) { $defined_vars=get_defined_vars(); $result=Array(); $reverse_key=Array(); $original_value=Array(); foreach( $defined_vars as $source_key => $source_value){ if($source_value==='__undefined__') break; $original_value[$source_key]=$$source_key; $new_test_value="PREFIX".rand()."SUFIX"; $reverse_key[$new_test_value]=$source_key; $$source_key=$new_test_value; } foreach($GLOBALS as $key => &$value){ if( is_string($value) && isset($reverse_key[$value]) ) { $result[$key]=&$value; } } foreach( $original_value as $source_key => $original_value){ $$source_key=$original_value; } return $result; } $a = 'A'; $b = 'B'; $c = '999'; $myArray=Array ('id'=>'id123','name'=>'Foo'); print_r(compact_assoc($a,$b,$c,$myArray) ); //print Array ( [a] => A [b] => B [c] => 999 [myArray] => Array ( [id] => id123 [name] => Foo ) ) 

Если переменная является взаимозаменяемой, вы должны иметь логику где- то, определяющую, какая переменная используется. Все, что вам нужно сделать, это поместить имя переменной в $variable в эту логику, пока вы делаете все остальное.

Я думаю, нам все сложно понять, для чего вам это нужно. Образец кода или объяснение того, что вы на самом деле пытаетесь сделать, могут помочь, но я подозреваю, что вы способ, и это слишком сильно задумано.

Для этого у меня действительно есть пример использования.

У меня есть функция cacheVariable ($ var) (ok, у меня есть кеш функции ($ key, $ value), но я хотел бы иметь функцию, о которой упоминалось).

Цель состоит в том, чтобы сделать:

 $colour = 'blue'; cacheVariable($colour); 

 // another session 

 $myColour = getCachedVariable('colour'); 

Я пробовал с

 function cacheVariable($variable) { $key = ${$variable}; // This doesn't help! It only gives 'variable'. // do some caching using suitable backend such as apc, memcache or ramdisk } 

Я также пробовал

 function varName(&$var) { $definedVariables = get_defined_vars(); $copyOfDefinedVariables = array(); foreach ($definedVariables as $variable=>$value) { $copyOfDefinedVariables[$variable] = $value; } $oldVar = $var; $var = !$var; $difference = array_diff_assoc($definedVariables, $copyOfDefinedVariables); $var = $oldVar; return key(array_slice($difference, 0, 1, true)); } 

Но это терпит неудачу … 🙁

Конечно, я мог бы продолжать делать кеш («цвет», $ цвет), но я ленивый, вы знаете …;)

Итак, я хочу, это функция, которая получает ORIGINAL имя переменной, поскольку она была передана функции. Внутри функции я никак не могу понять, что, как кажется. Передача get_defined_vars () по ссылке во втором примере выше помогла мне (спасибо Жан-Жаку Гегану за эту идею). Последняя функция начала работать, но она все еще только возвращала локальную переменную («переменная», а не «цвет»).

Я еще не пытался использовать get_func_args () и get_func_arg (), $ {} – constructs и key () вместе, но я полагаю, что это тоже не удастся.

У меня есть это:

  debug_echo(array('$query'=>$query, '$nrUsers'=>$nrUsers, '$hdr'=>$hdr)); 

Я бы предпочел это:

  debug_echo($query, $nrUsers, $hdr); 

Существующая функция отображает желтую рамку с красным контуром и показывает каждую переменную по имени и значению. Решение массива работает, но оно немного запутанно, когда нужно.

Это мой прецедент и да, это связано с отладкой. Я согласен с теми, кто ставит под вопрос его использование иначе.

Почему бы вам просто не построить простую функцию и не произнести ее?

 /** * Prints out $obj for debug * * @param any_type $obj * @param (string) $title */ function print_all( $obj, $title = false ) { print "\n<div style=\"font-family:Arial;\">\n"; if( $title ) print "<div style=\"background-color:red; color:white; font-size:16px; font-weight:bold; margin:0; padding:10px; text-align:center;\">$title</div>\n"; print "<pre style=\"background-color:yellow; border:2px solid red; color:black; margin:0; padding:10px;\">\n\n"; var_export( $obj ); print "\n\n</pre>\n</div>\n"; } print_all( $aUser, '$aUser' ); 

Вот мое решение, основанное на Jeremy Ruten

 class DebugHelper { function printVarNames($systemDefinedVars, $varNames) { foreach ($systemDefinedVars as $var=>$value) { if (in_array($var, $varNames )) { var_dump($var); var_dump($value); } } } } 

используй это

 DebugHelper::printVarNames( $systemDefinedVars = get_defined_vars(), $varNames=array('yourVar00', 'yourVar01') ); 

Используйте это, чтобы отключить переменные пользователя из global для проверки переменной на данный момент.

 function get_user_var_defined () { return array_slice($GLOBALS,8,count($GLOBALS)-8); } function get_var_name ($var) { $vuser = get_user_var_defined(); foreach($vuser as $key=>$value) { if($var===$value) return $key ; } } 

Я искал это, но просто решил передать имя, у меня обычно есть имя в буфере обмена.

 function VarTest($my_var,$my_var_name){ echo '$'.$my_var_name.': '.$my_var.'<br />'; } $fruit='apple'; VarTest($fruit,'fruit'); 

Я думаю, вы хотите узнать имя переменной с ее значением. Для этого вы можете использовать ассоциативный массив.

использовать имена переменных для ключей массива:

 $vars = array('FooBar' => 'a string'); 

Когда вы хотите получить имена переменных, используйте array_keys($vars) , он вернет массив тех имен переменных, которые использовались в вашем массиве $vars поскольку это ключи.

Я использую этот способ, чтобы получить имена столбцов таблицы в моем классе базы данных.

почему мы должны использовать глобальные переменные для получения имени переменной … мы можем использовать просто так, как показано ниже.

  $variableName = "ajaxmint"; echo getVarName('$variableName'); function getVarName($name) { return str_replace('$','',$name); } 

Его можно считать быстрым и грязным, но мое личное предпочтение заключается в использовании функции / метода, например:

 public function getVarName($var) { $tmp = array($var => ''); $keys = array_keys($tmp); return trim($keys[0]); } 

в основном он просто создает ассоциативный массив, содержащий один пустой / пустой элемент, используя в качестве ключа переменную, для которой вы хотите имя.

мы затем получаем значение этого ключа с помощью array_keys и возвращаем его.

очевидно, это становится беспорядочным быстро и нежелательно в производственной среде, но оно работает для представленной проблемы.

Вы можете использовать compact () для достижения этого.

 $FooBar = "a string"; $newArray = compact('FooBar'); 

Это создало бы ассоциативный массив с именем переменной в качестве ключа. Затем вы можете прокручивать массив, используя имя ключа, в котором вы нуждались.

 foreach($newarray as $key => $value) { echo $key; } 

Я действительно не вижу прецедента … Если вы напечатаете print_var_name ($ foobar), что будет так сложно (и другое) в том, что вы печатаете («foobar»)?

Потому что, даже если вы должны использовать это в функции, вы получите локальное имя переменной …

В любом случае, вот руководство по размышлениям, если там что-то нужно.