如何在PHP中将变量名称作为字符串?

Gar*_*hby 194 php

说我有这个PHP代码:

$FooBar = "a string";
Run Code Online (Sandbox Code Playgroud)

然后我需要一个这样的函数:

print_var_name($FooBar);
Run Code Online (Sandbox Code Playgroud)

打印:

FooBar
Run Code Online (Sandbox Code Playgroud)

任何想法如何实现这一目标?这在PHP中甚至可能吗?

Nic*_*sta 46

我想不出有效地做到这一点的方法,但我想出了这个.它适用于下面的有限用途.

<?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
)
Run Code Online (Sandbox Code Playgroud)

它基于调用函数的行来工作,在那里它找到你传入的参数.我想它可以扩展为使用多个参数,但是,正如其他人所说,如果你能更好地解释这种情况,另一种解决方案可能工作得更好.

  • 这是有效的,但前提是函数varName与要查找的变量在同一文件中定义. (2认同)

Jer*_*ten 40

您可以使用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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:要清楚,在PHP中没有好办法,这可能是因为你不应该这样做.做你正在做的事情可能有更好的方法.

  • 此代码可能不正确.检查f变量是否与VALUE发送的变量相同是一个非常愚蠢的想法.无数变量在任何给定点都是NULL.Myriads被设置为1.这只是疯了. (113认同)
  • 啊.去过慢;-)想法一样,但用$ GLOBALS代替.所以身份比较在等于标量值时产生真($ a ='foo'; $ b ='foo';断言($ a === $ b);)? (2认同)
  • 在很多情况下,此代码不会按预期运行. (2认同)

小智 29

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

$var_name = "FooBar";
$$var_name = "a string";
Run Code Online (Sandbox Code Playgroud)

那么你可以

print($var_name);
Run Code Online (Sandbox Code Playgroud)

要得到

FooBar
Run Code Online (Sandbox Code Playgroud)

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

  • 我使用过一个广泛使用变量变量的系统.让我警告你,真的很快变臭! (40认同)
  • 大多数情况下用户想要获取var的名称和值.想想"函数debugvar($ varname)",他打算将其称为"debugvar('foo')",因此调试将显示"foo = 123".使用变量变量,他们将得到'foo'是未定义的. (3认同)

IMS*_*SoP 19

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

  • "变量"只是指向别的东西的符号.在PHP中,它内部指向称为"zval"的东西,它实际上可以同时用于多个变量,因为它们具有相同的值(PHP实现了一种称为"copy-on-write"的东西,所以$foo = $bar不需要直接分配额外的内存)或因为它们已被引用(例如$foo =& $bar)分配(或传递给函数).所以zval没有名字.
  • 将参数传递给函数时,您正在创建一个变量(即使它是一个引用).你可以传递一些匿名的东西,比如"hello",但是一旦进入你的函数,它就是你命名的变量.这是相当基本的代码分离:如果一个函数在什么变量依赖使用被称为,这将是更像是一个goto比一个适当的独立机构.
  • 全局变量通常被认为是一个坏主意.这里有很多例子假设您想要"反映"的变量可以在其中找到$GLOBALS,但只有在您的代码结构严重且变量没有作用于某个函数或对象的情况下才会出现这种情况.
  • 变量名称可以帮助程序员读取他们的代码.重命名变量以更好地适应其目的是一种非常常见的重构实践,并且重点是它没有任何区别.

现在,我明白了这个愿望,调试(虽然有些建议的用法远不止于此),但作为一个通用的解决方案它实际上不是像你想的一样有用:如果你的调试功能,说你的变量称为"$文件",这可能仍然是代码中的几十个"$ file"变量中的任何一个,或者是一个名为"$ filename"的变量,但是传递给一个参数名为"$ file"的函数.

一个更有用的信息是在代码中调用调试函数的位置.由于您可以在编辑器中快速找到它,因此您可以查看自己输出的变量,甚至可以一次性将整个表达式传递给它(例如debug('$foo + $bar = ' . ($foo + $bar))).

为此,您可以在调试函数的顶部使用此代码段:

$backtrace = debug_backtrace();
echo '# Debug function called from ' . $backtrace[0]['file'] . ' at line ' . $backtrace[0]['line'];
Run Code Online (Sandbox Code Playgroud)


Seb*_*oli 13

我出于调试原因制作了检查功能.它就像类固醇上的print_r(),就像Krumo一样,但对物体更有效.我想添加var名称检测,并在此页面上受到Nick Presta帖子的启发.它会检测作为参数传递的任何表达式,而不仅仅是变量名称.

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

这工作正常:死(检查($这个 - >的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'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);

}
Run Code Online (Sandbox Code Playgroud)

以下是检查器函数(和我的dInspect类)的实例:

http://inspect.ip1.cc

文本在该页面中是西班牙语,但代码简洁且易于理解.


Wor*_*man 13

PHP.net上的Lucas提供了一种检查变量是否存在的可靠方法.在他的示例中,他遍历变量的全局变量数组(或范围数组)的副本,将值更改为随机生成的值,并检查复制的数组中生成的值.

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;
}
Run Code Online (Sandbox Code Playgroud)

然后尝试:

$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
Run Code Online (Sandbox Code Playgroud)

请务必在PHP.net上查看他的帖子:http://php.net/manual/en/language.variables.php


adi*_*lbo 11

这正是你想要的 - 它是一个随时可用的"复制和放入"函数,它回显给定var的名称:

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);
}
Run Code Online (Sandbox Code Playgroud)

用法:print_var_name($ FooBar)

打印:FooBar

提示 现在您可以重命名该功能,它仍然可以工作,并且可以在一行中多次使用该功能!感谢@Cliffordlife

  • 很酷,谢谢你.我将$ pat线稍微修改为`$ pat ='#(.*)'.__ FUNCTION__.'*?\(*?(.*)*?\)(.*)#i';`这样我不关心调用这个调试函数是什么,我得到了传递给函数的确切内容即$ hello ,或"你好"(我把传入的变量的$ match放在同一行) (3认同)
  • 很棒的一段代码!谢谢!但是,它似乎并非在所有情况下都有效。使用 php 7.2.19 在我的 ubuntu 18.04 上测试的结果:在同一行代码上多次使用时不起作用,无论它是在一个还是单独的表达式中使用,因为它返回最后一个变量的名称线。如果它在同一个表达式中但在不同的行中使用,则它起作用。在不同行的不同表达式中使用它起作用。 (2认同)
  • 这是一个非常有创意的解决方案。功能优秀!此外,OP没有具体询问,因为我认为他正在隔离他的问题,但是,我认为OP也想要值输出。因此,为了避免编写更多的客户端代码,可以将函数的最后一行替换为: `echo '&lt;pre&gt;' 。修剪($var)。'='。print_r(当前(func_get_args()), true) 。'&lt;/pre&gt;';` 输出 FooBar = 一个字符串,并且也考虑数组。 (2认同)

小智 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;  
}
?>
Run Code Online (Sandbox Code Playgroud)

@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
?>
Run Code Online (Sandbox Code Playgroud)


小智 5

许多回复质疑这是否有用。但是,获取变量的引用非常有用。特别是在对象和$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}";
}
Run Code Online (Sandbox Code Playgroud)

上面的例子:

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
Run Code Online (Sandbox Code Playgroud)