如何在 PHP 中以字符串形式获取变量名


How to get a variable name as a string in PHP?

>假设我有这个PHP代码:

$FooBar = "a string";

然后我需要这样的函数:

print_var_name($FooBar);

其中打印:

FooBar

任何想法如何实现这一目标?这在 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
)

它基于调用函数的行工作,在该行中查找您传入的参数。我想它可以扩展到使用多个参数,但正如其他人所说,如果你能更好地解释情况,另一种解决方案可能会更好。

您可以使用 get_defined_vars(( 查找与您尝试查找其名称的值相同的变量的名称。显然,这并不总是有效,因为不同的变量通常具有相同的值,但这是我能想到的唯一方法。

编辑: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;
}

编辑:需要明确的是,在PHP中没有好的方法可以做到这一点,这可能是因为你不应该这样做。可能有更好的方法来做你想做的事情。

您可以考虑更改方法并使用变量变量名称?

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

然后你可以

print($var_name);

要得到

FooBar

这是关于变量的PHP手册的链接

似乎没有人提到为什么这是 a( 困难和 b( 不明智的根本原因:

  • "变量"只是一个指向其他事物的符号。在 PHP 中,它在内部指向称为"zval"的东西,它实际上可以同时用于多个变量,要么是因为它们具有相同的值(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'];

这正是你想要的 - 它是一个现成的"复制和插入"函数,回显给定变量的名称:

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 '<pre>' . trim($var) . ' = ' . print_r(current(func_get_args()), true) . '</pre>';
}

用法:print_var_name($FooBar(

打印:福吧

提示
现在您可以重命名该函数,它仍然可以工作,也可以在一行中多次使用该函数!感谢@Cliffordlife
我添加了更好的输出!得益于@Blue水

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

出于调试原因,我做了一个检查功能。 这就像类固醇上的print_r((,很像克鲁莫,但对物体更有效。 我想添加var名称检测,并提出了这个,灵感来自Nick Presta在此页面上的帖子。 它检测作为参数传递的任何表达式,而不仅仅是变量名称。

这只是检测传递的表达式的包装函数。适用于大多数情况。如果在同一代码行中多次调用该函数,它将不起作用。

这工作正常: die(inspect($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

该页面中的文本是西班牙语的,但代码简洁且非常易于理解。

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

许多回复质疑这样做的用处。但是,获取变量的引用可能非常有用。特别是在有物体和$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

改编自上述许多变量的答案,性能良好,只需一个$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((好的,我有一个函数cache($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(( 对我有所帮助(感谢让-雅克·盖根的想法(。后一个函数开始工作,但它仍然只返回局部变量("变量",而不是"颜色"(。

我还没有尝试结合使用 get_func_args(( 和 get_func_arg((,${}-构造和 key((,但我认为它也会失败。

我有这个:

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

我更喜欢这个:

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

现有函数显示一个带有红色轮廓的黄色框,并按名称和值显示每个变量。阵列解决方案可以工作,但在需要时键入起来有点复杂。

这是我的用例,是的,它确实与调试有关。我同意那些质疑其使用的人。

这是我

基于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')
);

你可以使用 compact(( 来实现这一点。

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

这将创建一个以变量名称作为键的关联数组。 然后,您可以在需要的位置使用键名称遍历数组。

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

你想知道变量名称及其值。您可以使用关联数组来实现此目的。

对数组键使用变量名称:

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

当您想要获取变量名称时,请使用 array_keys($vars) ,它将返回在$vars数组中使用的变量名称的数组作为键。

这就是我的做法

function getVar(&$var) {
    $tmp = $var; // store the variable value
    $var = '_$_%&33xc$%^*7_r4'; // give the variable a new unique value
    $name = array_search($var, $GLOBALS); // search $GLOBALS for that unique value and return the key(variable)
    $var = $tmp; // restore the variable old value
    return $name;
}

用法

$city  = "San Francisco";
echo getVar($city); // city

注意:由于与$GLOBALS array_search中的错误,某些PHP 7版本将无法正常工作,但是所有其他版本都可以工作。

请参阅此 https://3v4l.org/UMW7V

PHP 中没有可以输出变量名称的预定义函数。但是,您可以使用 get_defined_vars() 的结果,它返回作用域中定义的所有变量,包括名称和值。下面是一个示例:

<?php
    // Function for determining the name of a variable
    function getVarName(&$var, $definedVars=null) {
        $definedVars = (!is_array($definedVars) ? $GLOBALS : $definedVars);
        $val = $var;
        $rand = 1;
        while (in_array($rand, $definedVars, true)) {
            $rand = md5(mt_rand(10000, 1000000));
        }
        $var = $rand;
         
        foreach ($definedVars as $dvName=>$dvVal) {
            if ($dvVal === $rand) {
                $var = $val;
                return $dvName;
            }
        }
         
        return null;
    }
 
    // the name of $a is to be determined.   
    $a = 1;
     
    // Determine the name of $a
    echo getVarName($a);
?>

阅读更多 如何在 PHP 中将变量名称作为字符串获取?

你为什么不直接构建一个简单的函数并告诉它呢?

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

我一直在寻找这个,但只是决定传递名称,无论如何我通常都会在剪贴板中拥有该名称。

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

我知道这很旧并且已经回答了,但我实际上正在寻找这个。我发布这个答案是为了节省人们一点时间来完善一些答案。

选项 1:

$data = array('$FooBar');  
$vars = [];  
$vars = preg_replace('/^''$/', '', $data); 
$varname = key(compact($vars));  
echo $varname;

指纹:

福吧

无论出于何种原因,您都会发现自己处于这种情况,它确实有效。

.
选项 2:

$FooBar = "a string";  
$varname = trim(array_search($FooBar, $GLOBALS), " 't.");  
echo $varname;

如果$FooBar具有唯一值,它将打印"FooBar"。如果$FooBar为空或空,它将打印它找到的第一个空或空字符串的名称。

它可以这样使用:

if (isset($FooBar) && !is_null($FooBar) && !empty($FooBar)) {
    $FooBar = "a string";
    $varname = trim(array_search($FooBar, $GLOBALS), " 't.");
}

其他用途:

耸肩

function varsToArrayAssoc(...$arguments){
  
    $bt   = debug_backtrace();
    $file = file($bt[0]['file']);
    $src  = $file[$bt[0]['line']-1];
    $pat = '#(.*)'.__FUNCTION__.' *?'( *?(.*) *?')(.*)#i';
    $vars  =explode(',',substr_replace(trim(preg_replace($pat, '$2', $src)) ,"", -1));
    $result=[];
    foreach(func_get_args() as $key=>$v){
        $index=trim(explode('$',$vars[$key])[1]);
        $result[$index]=$v;
    }
    return $result;
}
$a=12;
$b=13;
$c=123;
$d='aa';
var_dump(varsToArrayAssoc($a,$b,$c,$d));

使用它来将用户变量从全局中分离以检查当前变量。

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]);
}

基本上,它只是创建一个包含一个 null/empty 元素的关联数组,使用您想要命名的变量作为键。

然后我们使用 array_keys 获取该键的值并返回它。

显然,这很快就会变得混乱,并且在生产环境中是不可取的,但它适用于所提出的问题。

为什么我们必须使用全局变量来获取变量名...我们可以像下面这样简单地使用。

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

我真的看不到用例...如果你要输入print_var_name($foobar(来代替输入print("foobar"(有什么困难(和不同(的?

因为即使你在函数中使用它,你也会得到变量的本地名称......

无论如何,这是反射手册,以防您需要的东西。