php 如何在PHP中将变量名作为字符串获取?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/255312/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get a variable name as a string in PHP?
提问by Gary Willoughby
Say i have this PHP code:
假设我有这个 PHP 代码:
$FooBar = "a string";
i then need a function like this:
然后我需要一个这样的功能:
print_var_name($FooBar);
which prints:
打印:
FooBar
Any Ideas how to achieve this? Is this even possible in PHP?
任何想法如何实现这一目标?这在PHP中甚至可能吗?
采纳答案by Jeremy Ruten
You could use get_defined_vars()to find the name of a variable that has the same value as the one you're trying to find the name of. Obviously this will not always work, since different variables often have the same values, but it's the only way I can think of to do this.
您可以使用get_defined_vars()来查找与您要查找的名称具有相同值的变量的名称。显然这并不总是有效,因为不同的变量通常具有相同的值,但这是我能想到的唯一方法。
Edit: get_defined_vars() doesn't seem to be working correctly, it returns 'var' because $var is used in the function itself. $GLOBALS seems to work so I've changed it to that.
编辑: 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: to be clear, there is no good way to do this in PHP, which is probably because you shouldn't have to do it. There are probably better ways of doing what you're trying to do.
编辑:需要明确的是,在 PHP 中没有好的方法可以做到这一点,这可能是因为您不应该这样做。可能有更好的方法来做你想做的事情。
回答by Nick Presta
I couldn't think of a way to do this efficiently either but I came up with this. It works, for the limited uses below.
我也想不出一种方法来有效地做到这一点,但我想出了这个。它适用于以下有限用途。
shrug
耸耸肩
<?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
)
It works based on the line that called the function, where it finds the argument you passed in. I suppose it could be expanded to work with multiple arguments but, like others have said, if you could explain the situation better, another solution would probably work better.
它基于调用函数的行,在其中找到您传入的参数。我想它可以扩展为使用多个参数,但是,就像其他人所说的那样,如果您能更好地解释这种情况,另一种解决方案可能会更好地工作。
回答by Jeremy Ruten
You might consider changing your approach and using a variable variable name?
您可能会考虑更改您的方法并使用可变变量名称?
$var_name = "FooBar";
$$var_name = "a string";
then you could just
那么你就可以
print($var_name);
to get
要得到
FooBar
Here's the link to the PHP manual on Variable variables
回答by IMSoP
No-one seems to have mentioned the fundamental reasons whythis is a) hard and b) unwise:
没有人似乎已经提到的根本原因,为什么这是一个)硬盘和b)不明智的:
- A "variable" is just a symbol pointing at something else. In PHP, it internally points to something called a "zval", which can actually be used for multiple variables simultaneously, either because they have the same value (PHP implements something called "copy-on-write" so that
$foo = $bardoesn't need to allocate extra memory straight away) or because they have been assigned (or passed to a function) by reference (e.g.$foo =& $bar). So a zval has no name. - When you pass a parameter to a function you are creating a newvariable (even if it's a reference). You could pass something anonymous, like
"hello", but once inside your function, it's whatever variable you name it as. This is fairly fundamental to code separation: if a function relied on what a variable usedto be called, it would be more like agotothan a properly separate function. - Global variables are generally considered a bad idea. A lot of the examples here assume that the variable you want to "reflect" can be found in
$GLOBALS, but this will only be true if you've structured your code badly and variables aren't scoped to some function or object. - Variable names are there to help programmers read their code. Renaming variables to better suit their purpose is a very common refactoring practice, and the whole point is that it doesn't make any difference.
- “变量”只是指向其他事物的符号。在 PHP 中,它在内部指向一个叫做“zval”的东西,它实际上可以同时用于多个变量,或者因为它们具有相同的值(PHP 实现了一种叫做“写入时复制”的东西,因此
$foo = $bar不需要立即分配额外的内存)或因为它们已通过引用分配(或传递给函数)(例如$foo =& $bar)。所以 zval 没有名字。 - 当您将参数传递给函数时,您正在创建一个新变量(即使它是一个引用)。你可以传递匿名的东西,比如
"hello",但是一旦进入你的函数,它就是你命名的任何变量。这对于代码分离来说是相当基础的:如果一个函数依赖于一个变量曾经被调用的内容,那么它更像是一个而goto不是一个正确分离的函数。 - 全局变量通常被认为是一个坏主意。此处的许多示例都假设您要“反映”的变量可以在 中找到
$GLOBALS,但只有在您的代码结构不当并且变量的范围不限于某个函数或对象时,这才是正确的。 - 变量名可以帮助程序员阅读他们的代码。重命名变量以更好地适应其目的是一种非常常见的重构实践,重点是它没有任何区别。
Now, I understand the desire for this for debugging (although some of the proposed usages go far beyond that), but as a generalised solution it's not actually as helpful as you might think: if your debug function says your variable is called "$file", that could still be any one of dozens of "$file" variables in your code, or a variable which you have called "$filename" but are passing to a function whose parameter is called "$file".
现在,我理解了调试的愿望(尽管一些建议的用法远不止于此),但作为一个通用的解决方案,它实际上并不像你想象的那么有用:如果你的调试函数说你的变量被称为“$file ",它仍然可能是代码中数十个 "$file" 变量中的任何一个,或者是您已称为 "$filename" 但传递给其参数名为 "$file" 的函数的变量。
A far more useful piece of information is where in your code the debug function was called from. Since you can quickly find this in your editor, you can see which variable you were outputting for yourself, and can even pass whole expressions into it in one go (e.g. debug('$foo + $bar = ' . ($foo + $bar))).
一条更有用的信息是在您的代码中调用调试函数的位置。由于您可以在编辑器中快速找到它,因此您可以查看自己输出的是哪个变量,甚至可以一次性将整个表达式传递给它(例如debug('$foo + $bar = ' . ($foo + $bar)))。
For that, you can use this snippet at the top of your debug function:
为此,您可以在调试功能的顶部使用此代码段:
$backtrace = debug_backtrace();
echo '# Debug function called from ' . $backtrace[0]['file'] . ' at line ' . $backtrace[0]['line'];
回答by adilbo
This is exactly what you want - its a ready to use "copy and drop in" function that echo the name of a given var:
这正是您想要的 - 它是一个随时可以使用的“复制并放入”函数,可以回显给定 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, '', $src);
// print to browser
echo trim($var);
}
USAGE: print_var_name($FooBar)
用法:print_var_name($FooBar)
PRINT: FooBar
打印:FooBar
HINTNow you can rename the function and it will still work and also use the function several times in one line! Thanks to @Cliffordlife
提示现在您可以重命名该函数,它仍然可以工作,并且可以在一行中多次使用该函数!感谢@Cliffordlife
回答by Workman
Lucas on PHP.net provided a reliable way to check if a variable exists. In his example, he iterates through a copy of the global variable array (or a scoped array) of variables, changes the value to a randomly generated value, and checks for the generated value in the copied array.
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;
}
Then try:
然后尝试:
$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
Be sure to check his post on PHP.net: http://php.net/manual/en/language.variables.php
请务必查看他在 PHP.net 上的帖子:http: //php.net/manual/en/language.variables.php
回答by Sebastián Grignoli
I made an inspection function for debugging reasons. It's like print_r() on steroids, much like Krumo but a little more effective on objects. I wanted to add the var name detection and came out with this, inspired by Nick Presta's post on this page. It detects any expression passed as an argument, not only variable names.
出于调试的原因,我做了一个检查功能。这就像类固醇上的 print_r() ,很像 Krumo 但在对象上更有效一些。我想添加 var 名称检测,并受到 Nick Presta 在此页面上的帖子的启发,并提出了这一点。它检测作为参数传递的任何表达式,而不仅仅是变量名称。
This is only the wrapper function that detects the passed expression. Works on most of the cases. It will not work if you call the function more than once in the same line of code.
这只是检测传递的表达式的包装函数。适用于大多数情况。如果您在同一行代码中多次调用该函数,它将不起作用。
This works fine: die(inspect($this->getUser()->hasCredential("delete")));
这工作正常:死(检查($this->getUser()->hasCredential("delete")));
inspect() is the function that will detect the passed expression.
inspect() 是检测传递的表达式的函数。
We get: $this->getUser()->hasCredential("delete")
我们得到: $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);
}
Here's an example of the inspector function (and my dInspect class) in action:
这是检查器功能(和我的 dInspect 类)的示例:
Texts are in spanish in that page, but code is concise and really easy to understand.
该页面中的文本为西班牙语,但代码简洁且易于理解。
回答by Sebastián Grignoli
From php.net
来自php.net
@Alexandre - short solution
@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 - usage
@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
?>
回答by K. Brunner
Many replies question the usefulness of this. However, getting a reference for a variable can be very useful. Especially in cases with objects and $this. My solution works with objects, and as property defined objects as well:
许多答复质疑这是否有用。但是,获取变量的引用可能非常有用。特别是在对象和$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}";
}
Example for the above:
上面的例子:
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
回答by user1933288
Adapted from answers above for many variables, with good performance, just one $GLOBALS scan for many
改编自上述许多变量的答案,具有良好的性能,只需一次 $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
)
)

