Как получить имя переменной в виде строки в PHP?
скажем, у меня есть этот PHP код:
$FooBar = "a string";
мне тогда нужна такая функция:
print_var_name($FooBar);
, который печатает:
FooBar
есть идеи, как этого достичь? Возможно ли это в PHP?
22 ответов
можно использовать get_defined_vars () чтобы найти имя переменной, которая имеет то же значение, что и та, которую вы пытаетесь найти. Очевидно, это не всегда будет работать, поскольку разные переменные часто имеют одинаковые значения, но это единственный способ, который я могу придумать.
Edit: get_defined_vars (), похоже, работает неправильно, он возвращает 'var', потому что $var используется в самой функции. $ GLOBALS, кажется, работает, поэтому я изменил его на что.
function print_var_name($var) {
foreach($GLOBALS as $var_name => $value) {
if ($value === $var) {
return $var_name;
}
}
return false;
}
Edit: чтобы быть ясным, нет хорошего способа сделать это в 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
). Так звал без имени. - когда вы передаете параметр функции, вы создаете новая переменной (даже если это ссылка). Вы можете передать что-то анонимное, как
"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 и вышел с этим, вдохновленный сообщением Ника Преста на этой странице. Он обнаруживает любое выражение, переданное в качестве аргумента, а не только имена переменных.
Это только функция-оболочка, которая обнаруживает переданное выражение. Работает над большинством дел. Он не будет работать, если вы вызываете функцию несколько раз в одной строке кода.
Это прекрасно работает: умри (проверить( $this - >getUser () - >hasCredential ("удалить")));
inspect () - это функция, которая обнаружит переданное выражение.
получаем: $this - >getUser () - >hasCredential ("удалить")
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);
}
вот пример функции inspector (и моего класса dInspect) в действие:
тексты на испанском языке на этой странице, но код является кратким и очень легко понять.
Лукас на 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
от 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
?>
многие ответы ставят под сомнение полезность этого. Однако получение ссылки на переменную может быть очень полезным. Особенно в случаях с объектами и это. Мое решение работает с объектами, а также с объектами, определенными свойствами:
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
Это именно то, что вы хотите - его готовая к использованию функция "копировать и опускать", которая повторяет имя данного 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 = '#(.*)'.__FUNCTION__.' *?\( *?(.*) *?\)(.*)#i';
// extract $varname from match no 2
$var = preg_replace($pat, '', $src);
// print to browser
echo trim($var);
}
использование: print_var_name ($FooBar)
печать: FooBar
подсказка Теперь вы можете переименовать функцию и она будет работать, а также использовать функцию несколько раз в одной строке! Благодаря @Cliffordlife
адаптировано из ответов выше для многих переменных, с хорошей производительностью, только один $ 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
)
)
если переменная взаимозаменяема, вы должны иметь logic где-то это определяет, какая переменная используется. Все, что вам нужно сделать, это поместить имя переменной в $variable
в рамках этой логики, пока вы делаете все остальное.
Я думаю, нам всем трудно понять, для чего вам это нужно. Пример кода или объяснение того, что вы на самом деле пытаетесь do может помочь, но я подозреваю, что Вы путь,путь overthinking этот.
у меня на самом деле есть действительный вариант использования для этого.
у меня есть функция cacheVariable($var) (хорошо, у меня есть кэш функций($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));
}
но это также не удается... :(
конечно, я мог бы продолжать делать кэш ("цвет", $colour), но я ленив, вы знаете... ;)
Итак, я хочу функцию, которая получает исходное имя переменной, поскольку она была передана функции. Внутри функции нет никакого способа узнать это, как кажется. Проходя get_defined_vars() по ссылке выше во втором примере мне помог (спасибо Жан-Жак Guegan за эту идею) несколько. Последняя функция начала работать, но по-прежнему возвращала только локальную переменную ("переменная", а не "цвет").
я еще не пробовал использовать get_func_args () и get_func_arg (), ${}- конструкции и 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')
);
Я искал это, но просто решил передать имя, у меня обычно есть имя в буфере обмена в любом случае.
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);
}
используйте это для отсоединения пользовательских переменных от глобальных для проверки переменной в данный момент.
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 ;
}
}
Это можно считать быстрым и грязным, но мое личное предпочтение-использовать такую функцию / метод:
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), что так сложно (и отличается) о наборе print ("foobar") вместо этого?
потому что даже если бы вы использовали это в функции, вы бы получили локальное имя переменной...
в любом случае, вот руководство по отражению на случай, если вам там что-то понадобится.