如何在PHP中获得一个string的variables名?
说我有这个PHP代码:
$FooBar = "a string";
然后我需要一个这样的function:
print_var_name($FooBar);
打印:
FooBar
任何想法如何实现这一目标? 这甚至可能在PHP?
你可以使用get_defined_vars()来find一个variables的名字,这个variables的名字和你试图find这个名字的variables的名字相同。 显然这不会总是有效,因为不同的variables通常具有相同的值,但是这是我唯一能想到的方法。
编辑:get_defined_vars()似乎没有正常工作,它返回“var”,因为$ var在函数本身中使用。 $全球似乎工作,所以我已经改变了。
function print_var_name($var) { foreach($GLOBALS as $var_name => $value) { if ($value === $var) { return $var_name; } } return false; }
编辑:要清楚,没有好办法在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 )
它的工作原理是基于调用函数的那一行,在那里它find了你传入的参数。我想这个函数可以扩展到多个参数一起工作,但是和其他人一样,如果你能更好地解释这个情况,另一个解决scheme可能会工作得更好。
你可能会考虑改变你的方法,并使用一个variables名称?
$var_name = "FooBar"; $$var_name = "a string";
那么你可以
print($var_name);
要得到
FooBar
这里是关于variablesvariables的PHP手册的链接
没有人似乎提到了这样的根本原因:a)困难和b)不明智:
- “variables”只是一个指向别的东西的符号。 在PHP中,它内部指向一个名为“zval”的东西,它可以同时用于多个variables,或者是因为它们具有相同的值(PHP实现了所谓的“copy-on-write”),所以
$foo = $bar
不需要马上分配额外的内存),或者因为它们已经被引用(例如$foo =& $bar
)分配(或传递给一个函数)。 所以一个zval没有名字。 - 当你传递一个参数给一个函数时,你正在创build一个新的variables(即使它是一个引用)。 你可以传递一些匿名的东西,比如
"hello"
,但是一旦进入你的函数,它就是你指定的任何variables。 这对于代码分离来说是相当基础的:如果一个函数依赖于一个variables被调用,它将更像是一个goto
不是一个正确分离的函数。 - 全局variables通常被认为是一个坏主意。 这里的很多例子都假设你想要“反映”的variables可以在
$GLOBALS
find,但是只有当你的代码构造的很糟糕,variables没有被作用于某个函数或者对象时,这才是真实的。 - variables名称可以帮助程序员读取他们的代码。 重命名variables以更好地适合他们的目的是一个非常常见的重构实践,而且重要的是它没有任何区别。
现在,我理解debugging的愿望(尽pipe一些build议的用法远远超出了这个范围),但作为一个通用的解决scheme,它并不像你想象的那样有帮助:如果你的debugging函数说你的variables被称为“$ file “,这仍然可以是你的代码中的几十个”$ file“variables中的任何一个,或者是一个你称为”$ filename“但是传递给一个函数的参数被称为”$ file“的variables。
一个更有用的信息是你的代码中调用debugging函数的地方。 既然你可以在你的编辑器中快速find它,你可以看到你自己输出了哪个variables,甚至可以一次性传入整个expression式(例如debug('$foo + $bar = ' . ($foo + $bar))
)。
为此,您可以在debuggingfunction的顶部使用这段代码:
$backtrace = debug_backtrace(); echo '# Debug function called from ' . $backtrace[0]['file'] . ' at line ' . $backtrace[0]['line'];
我为了debugging的原因做了一个检查function。 这就像print_r()类似于类固醇,很像Krumo,但对物体更有效一些。 我想添加var名称检测,并出现在这个页面上,由Nick Presta的post启发。 它检测作为parameter passing的任何expression式,而不仅仅是variables名称。
这只是检测传递的expression式的包装函数。 适用于大多数情况。 如果您在相同的代码行中多次调用该函数,它将不起作用。
这工作正常:死( 检查( $ this-> getUser() – > hasCredential(“删除”) ) );
inspect()是将检测传递的expression式的函数。
我们得到: $ 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); }
下面是检查器function(和我的dInspect类)的一个例子:
文本在西class牙文页面,但代码简洁,真正容易理解。
PHP.net上的Lucas提供了一个可靠的方法来检查variables是否存在。 在他的例子中,他遍历全局variables数组(或范围数组)的variables副本,将值更改为随机生成的值,并检查复制数组中的生成值。
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上检查他的post: http : //php.net/manual/en/language.variables.php
许多回复质疑这个的有用性。 但是,获取variables的引用可能非常有用。 特别是在对象和$ this的情况下。 我的解决scheme与对象一起工作,并作为属性定义的对象:
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
从php.net
@Alexandre – 简短的解决scheme
<?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 ?>
这正是你想要的 – 准备好使用“copy and drop in”函数来回显给定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 = '#(.*)print_var_name *?\( *?\$(.*) *?\)(.*)#i'; // extract $varname from match no 2 $var = preg_replace($pat, '$2', $src); // print to browser echo trim($var); }
USAGE:print_var_name($ FooBar)
打印:FooBar
提示这不是防弹的:如果函数被多次调用(在一行中),它将会失败!
如果variables是可互换的,那么必须有逻辑确定哪个variables被使用。 所有你需要做的就是把variables名放在$variable
logic $variable
中,而你正在做其他的事情。
我想我们都很难理解你需要什么。 示例代码或者你实际上想要做什么的解释可能会有所帮助,但是我怀疑你是这样做的。
我其实有一个有效的用例。
我有一个函数cacheVariable($ var)(好吧,我有一个函数caching($键,$值),但我想有一个函数提到)。
目的是做:
$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)); }
但是这也失败了…… 🙁
当然,我可以继续做caching('颜色',$颜色),但我很懒,你知道…;)
所以,我想要的是一个函数,获取variables的原始名称,因为它被传递给一个函数。 在函数内部,我无法知道这一点。 在上面的第二个例子中通过引用传递get_defined_vars()有助于我(感谢Jean-Jacques Guegan的这个想法)。 后者函数开始工作,但它仍然只是保持返回局部variables('variables',而不是'颜色')。
我还没有尝试过使用get_func_args()和get_func_arg(),$ {} – constructs和key(),但是我认为它也会失败。
我有这个:
debug_echo(array('$query'=>$query, '$nrUsers'=>$nrUsers, '$hdr'=>$hdr));
我宁愿这样做:
debug_echo($query, $nrUsers, $hdr);
现有function显示一个带红色轮廓的黄色框,并按名称和值显示每个variables。 arrays解决scheme工作,但有点复杂,需要时键入。
这是我的用例,是的,它确实与debugging有关。 我同意那些质疑其使用的人。
从上面的答案适应许多variables,具有良好的性能,只是一个$ 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 ) )
你为什么不build立一个简单的function,并告诉它?
/** * 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
解决scheme
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') );
此时使用此从全局分离用户variables来检查variables。
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 ; } }
我正在寻找这个,但只是决定通过名称,反正我通常在剪贴板的名称。
function VarTest($my_var,$my_var_name){ echo '$'.$my_var_name.': '.$my_var.'<br />'; } $fruit='apple'; VarTest($fruit,'fruit');
我想你想知道它的值的variables名称。 您可以使用关联数组来实现这一点。
使用数组键的variables名称:
$vars = array('FooBar' => 'a string');
当你想得到variables名时,使用array_keys($vars)
,它将返回一个在$vars
数组中使用的variables名的数组,因为它是键。
我用这种方式来获取我的数据库类中的表的列名。
为什么我们必须使用全局variables来获取variables名…我们可以像下面那样使用。
$variableName = "ajaxmint"; echo getVarName('$variableName'); function getVarName($name) { return str_replace('$','',$name); }
它可能被认为是快速和肮脏的,但我个人的偏好是使用这样的函数/方法:
public function getVarName($var) { $tmp = array($var => ''); $keys = array_keys($tmp); return trim($keys[0]); }
基本上它只是创build一个包含一个null / empty元素的关联数组,使用您想要的名称作为variables的关键字。
然后我们使用array_keys获取该键的值并返回它。
显然这会变得凌乱并且在生产环境中不可取,但是对于所提出的问题是有效的。
你可以使用compact()来实现这一点。
$FooBar = "a string"; $newArray = compact('FooBar');
这将创build一个variables名为关键字的关联数组。 然后,您可以在需要的地方使用密钥名称遍历数组。
foreach($newarray as $key => $value) { echo $key; }
我真的没有看到用例…如果你要inputprint_var_name($ foobar),那么inputprint(“foobar”)又有什么困难(和不同)呢?
因为即使你在一个函数中使用它,你也会得到variables的本地名称。
无论如何,这里是reflection手册 ,以防在那里有你需要的东西。