将所有的PHP函数参数作为$key => $value数组获取?

8
<?php
function register_template(){
    print_r(func_get_args());
    # the result was an array ( [0] => my template [1] => screenshot.png [2] => nice template .. ) 

}

register_template(     # unkown number of arguments
    $name = "my template",
    $screenshot = "screenshot.png",
    $description = "nice template .. "
)
?>

但是,我希望结果数组的形式为$key => $value,其中$key代表参数名称。

1
为什么不将数组作为“register_template”参数传递呢? - Rizo
(相关)http://www.php.net/~derick/meeting-notes.html#named-parameters - Gordon
11个回答

15

PHP 不支持任意数量的命名参数。你要么在函数声明中决定一组固定数量的参数及其名称,要么只能获取值。

通常的解决方法是使用数组:

function register_template($args) {
    // use $args
}

register_template(array('name' => 'my template', ...));

1
我不需要使用数组作为输入。 - web lover
10
你需要这样做才能实现你想要达到的目标。 - deceze
我想听听你对我的答案的意见。 - Starx
1
@Starx 这并不是什么坏习惯。 - Mike B
使用这种方法,你如何访问参数?你能像 echo $args['name'] 这样做吗?还是必须使用类似 func_get_args 的东西? - compguy24

14

我想做同样的事情,但已经对已经给出的答案不太满意了...

尝试将以下内容添加到您的功能中 ->

$reflector = new ReflectionClass(__CLASS__);
$parameters = $reflector->getMethod(__FUNCTION__)->getParameters();

$args = array();
foreach($parameters as $parameter)
{
    $args[$parameter->name] = ${$parameter->name};
}
print_r($args);

我还没有考虑过尝试将这个功能作为自己的函数来实现,但可能可以...


1
这个完美无缺,非常感谢。成功将它压缩成了5行像砖头一样的代码,现在我可以随处使用它。虽然不是最漂亮的解决方案,但它可靠且稳定。 - dimitarvp
请注意,使用反射非常缓慢,不建议在生产中使用。 - Maksym Semenykhin

3

参数名称并不存在。frobnicate($a = "b")不是带参数调用语法,而只是一个赋值后跟随函数调用的技巧,用于代码文档,实际上并未被语言考虑在内。

通常接受的做法是提供一个关联数组形式的参数:frobnicate(array('a' => 'b'))


2

选项A)

<?php

function registerTemplateA() {
    // loop over every variable defined in the global scope,
    // such as those you created there when calling this function
    foreach($GLOBALS as $potentialKey => $potentialValue) {
        $valueArgs = func_get_args();
        if (in_array($potentialValue, $valueArgs)) {
            // this variable seems to match a _value_ you passed in
            $args[$potentialKey] = $potentialValue;
        }
    }
    // you now have an associative array in $args
    print_r($args);
}

registerTemplateA($name = "my template", $screenshot = "screenshot.png", $description = "nice template");

?>

Option B) 选项B
<?php

function registerTemplateB() {
    // passing in keys as args this time so we don't need to access global scope
    for ($i = 0; $i < func_num_args(); $i++) {
        // run following code on even args
        // (the even args are numbered as odd since it counts from zero)
        // `% 2` is a modulus operation (calculating remainder when dividing by 2)
        if ($i % 2 != 0) {
            $key = func_get_arg($i - 1);
            $value = func_get_arg($i);
            // join odd and even args together as key/value pairs
            $args[$key] = $value;
        }
    }
    // you now have an associative array in $args
    print_r($args);
}

registerTemplateB('name', 'my template', 'screenshot', 'screenshot.png', 'description', 'nice template');

?>

选项 C)
<?php

function registerTemplateC($args) {
    // you now have an associative array in $args
    print_r($args);
}

registerTemplateC(array('name' => 'my template', 'screenshot' => 'screenshot.png', 'description' => 'nice template'));

?>

结论:对于“最少代码”选项C是最好的。
(注意:这个答案是有效的PHP代码,有正确的开放和关闭标签,在PHP 5.2.x进行了测试,并且应该也可以在PHP 4上运行...所以如果您必须尝试一下。)

+1 对于正确处理具有可变参数的函数的方法。这是正确的方法。请参阅http://www.php.net/manual/en/function.func-get-args.php获取更多信息。 - Jason

1

很简单。只需将数组作为参数传递,然后在函数内部以$key => $value的形式访问即可。

更新

这是我能想到的最好的方法。

$vars = array("var1","var2"); //define the variable one extra time here
$$vars[0] = 'value1'; // or use $var1
$$vars[1] = 'value2'; // or use $var2

function myfunction() {
    global $vars;
    $fVars = func_get_args();
    foreach($fVars as $key=>$value) {
       $fvars[$vars[$key]] = $value;
       unset($fvar[$key]);
    }
    //now you have what you want var1=> value1
}

myfunction(array($$vars[0],$$vars[1]));

我还没有测试过...顺便说一下。但是你应该明白要点。


我不需要使用数组作为输入。 - web lover
除此之外,我没有看到任何简单的方法。 - Starx
4
许多没有任何好处的不良实践。 :) - deceze
@deceze,是的...我知道我的解决方案真的很凌乱...但那就是OP想要的,也是我给出的哈哈。 - Starx

1
将函数参数作为映射名称=>值获取
function test($a,$b,$c){

  // result map   nameParam=>value
  $inMapParameters=[];

   //get values of parameters
  $fnValueParameters=func_get_args();

  $method = new \ReflectionMethod($this, 'test');


      foreach ($method->getParameters() as $index=>$param) {

            $name = $param->getName();

            if($fnValueParameters[$index]==null){continue;}

            $inMapParameters["$name"]=$fnValueParameters[$index];
        }

}

1
class MyAwesomeClass
{
    public static function apple($kind, $weight, $color = 'green')
    {
        $args = self::funcGetNamedParams();
        print_r($args);
    }

    private static function funcGetNamedParams() {
        $func = debug_backtrace()[1]['function'];
        $args = debug_backtrace()[1]['args'];
        $reflector = new \ReflectionClass(__CLASS__);
        $params = [];
        foreach($reflector->getMethod($func)->getParameters() as $k => $parameter){
            $params[$parameter->name] = isset($args[$k]) ? $args[$k] : $parameter->getDefaultValue();
        }

        return $params;
    }
}

让我们来测试一下!

MyAwesomeClass::apple('Granny Smith', 250);

输出:

Array
(
    [kind] => Granny Smith
    [weight] => 250
    [color] => green
)

这是一个相当不错的解决方案。除了反射速度慢之外,有人知道使用这种方法是否存在任何缺点吗? - iSWORD

1
您可以通过使用 get_defined_vars() 来实现,但是不要忘记此函数会返回函数作用域内的所有变量。

例如:

<?php

function asd($q, $w, $rer){
    $test = '23ew';
    var_dump(get_defined_vars());
}

asd("qweqwe", 'ewrq', '43ewdsa');
?>

返回:
array(4) {
  ["q"]=>
  string(6) "qweqwe"
  ["w"]=>
  string(4) "ewrq"
  ["rer"]=>
  string(7) "43ewdsa"
  ["test"]=>
  string(4) "23ew"
}

0

不行,参数只能按位置传递。或许你可以发送一个数组?

<?php

function register_template(array $parameters) {
    var_dump($parameters);
}

register_template(# unkown number of arguments
    $name = "my template",
    $screenshot = "screenshot.png",
    $description = "nice template .. "
)


?>

传递给register_template()的第一个参数必须是数组。 - web lover

0

使用

function register_template($args){
    print_r ( $args ); // array (['name'] => 'my template' ...
    extract ($args);

    print $name; // my template
    print $screenshot;
}

register_templete ( array (
 "name" => "my template",
 "screenshot" => "screenshot.png",
 "description" => "nice template.."
));

我不需要使用数组作为输入。 - web lover

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接