Скажем, у меня есть этот код 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 по переменным переменным
Никто, кажется, не упомянул о фундаментальных причинах, почему это: а) жесткий и б) неразумный:
$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):
Тексты на испанском языке на этой странице, но код является кратким и очень простым для понимания.
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»)?
Потому что, даже если вы должны использовать это в функции, вы получите локальное имя переменной …
В любом случае, вот руководство по размышлениям, если там что-то нужно.