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

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

$FooBar = "a string";

i тогда нужна такая функция:

print_var_name($FooBar);

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

FooBar

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

Ответ 1

Вы можете использовать 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 нет хорошего способа сделать это, вероятно, потому, что вам не нужно это делать. Вероятно, есть лучшие способы сделать то, что вы пытаетесь сделать.

Ответ 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 );

?>

// Returns
Array
(
    [0] => $foo
    [1] => foo
)
Array
(
    [0] => $bar
    [1] => bar
)
Array
(
    [0] => $baz
    [1] => baz
)

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

Ответ 3

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

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

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

print($var_name);

чтобы получить

FooBar

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

Ответ 4

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

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

Ответ 5

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

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

Это прекрасно работает:  умереть (инспектировать ( $this- > GetUser() → hasCredential ( "Удалить" ) ));

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 try to find out it 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 match the function call and the last closing bracket
        preg_match( "#inspect\((.+)\)#", $line, $match );

        /* let 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

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

Ответ 6

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

Ответ 7

От 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;  
}
?>

@Лукас - использование

<?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
?>

Ответ 8

Многие ответы ставят под сомнение полезность этого. Однако получение ссылки на переменную может быть очень полезным. Особенно в случаях с объектами и $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}";
}

Пример для вышеперечисленного:

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

Ответ 9

Это именно то, что вы хотите - это готовая к использованию функция "копировать и вставить", которая отображает имя данной переменной:

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

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

ПЕЧАТЬ: FooBar

СОВЕТ Теперь вы можете переименовать функцию, и она все равно будет работать, а также использовать функцию несколько раз в одной строке! Благодаря @Cliffordlife

Ответ 10

Адаптированный из ответов выше для многих переменных, с хорошей производительностью, всего лишь одно сканирование 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
        )

)

Ответ 11

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

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

Ответ 12

У меня действительно есть допустимый прецедент для этого.

У меня есть функция 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));
}

Но это тоже не удается...: (

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

Итак, я хочу, это функция, которая получает ОРИГИНАЛЬНОЕ имя переменной, поскольку она была передана функции. Внутри функции я никак не могу понять, что, как кажется. Передача get_defined_vars() по ссылке во втором примере выше помогла мне (спасибо Жан-Жаку Гегану за эту идею). Последняя функция начала работать, но она все еще только возвращала локальную переменную ( "переменная", а не "цвет" ).

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

Ответ 13

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

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

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

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

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

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

Ответ 14

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

/**
 * 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' );

Ответ 15

Здесь мое решение на основе 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')
);

Ответ 16

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

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

$fruit='apple';
VarTest($fruit,'fruit');

Ответ 17

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

$FooBar = "a string";

$newArray = compact('FooBar');

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

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

Ответ 18

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

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

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

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

Ответ 19

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

    $variableName = "ajaxmint";

    echo getVarName('$variableName');

    function getVarName($name) {
        return str_replace('$','',$name);
    }

Ответ 20

Используйте это, чтобы отключить переменные пользователя из 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 ; 
    }
}

Ответ 21

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

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

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

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

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

Ответ 22

Я действительно не вижу прецедента... Если вы напечатаете print_var_name ($ foobar), что так тяжело (и другое) о печатании ( "foobar" )?

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

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