防止PHP函数作为参数传递时立即被调用的最佳方法?

时间:2018-07-22 14:18:02

标签: php closures

请考虑以下代码。它具有ensure_default()帮助程序,该帮助程序将变量设置为false时将默认值分配给变量:

function resource_intensive_lookup() {
    echo 'Running '.__FUNCTION__.'<br>';
    return 'default_value';
}

function ensure_default(&$var, $default_value)
{
    if (! $var) {
        $var = $default_value;
    }
}

$var = 'some_value';

ensure_default($var, resource_intensive_lookup());
print_r($var);

问题在于,即使$var设置为非假值,resoursive_intensive_lookup()仍将被调用。我可以通过仅传递函数名称作为参数并在call_user_func()中使用ensure_default()来防止这种情况,但是如果代码库具有更多类似于ensure_default()的函数,则这种方法的伸缩性将不会很好

我也尝试过使用闭包来防止不必要地调用resource_intensive_lookup(),但是当最初$ var开始时,不幸地将$var设置为Closure Object ( )而不是default_value设置为false:

$closure = function () {
    return resource_intensive_lookup();
};

function resource_intensive_lookup() {
    echo 'Running '.__FUNCTION__.'<br>';
    return 'default_value';
}

function ensure_default(&$var, $default_value)
{
    if (! $var) {
        $var = $default_value;
    }
}

$var = false;

ensure_default($var, $closure);
print_r($var);

3 个答案:

答案 0 :(得分:1)

您问题中的最后一个例子几乎不错。您需要更改:

$var = $default_value;

收件人:

$var = $default_value();

编辑:

如果您不想更改ensure_default,我能想到的唯一解决方案是创建自己的代理,如果ensure_default返回它,它将调用可调用对象并对其进行调用代理而不是原始的ensure_default

function ensure_default_with_callback(&$var, $default_value) {
    ensure_default($var, $default_value);

    if (is_callable($var)) {
        $var = $var();
    }
}

ensure_default_with_callback($var, $closure);
// you can also call it without closure
ensure_default_with_callback($var, "not a closure");

答案 1 :(得分:0)

如果您可以将初始化作为匿名函数传递,则只有在需要时才可以调用该函数...

function ensure_default(&$var, $default_value)
{
    if (! $var) {
        $var = $default_value();
    }
}

$var = 'some_value';   // Values used for testing
$var = null;

ensure_default($var, function () {
    echo 'Running '.__FUNCTION__.'<br>';
    return 'default_value';
});
print_r($var);

编辑:

如果您希望ensure_default()能够处理函数或文字值,则可以检查$default_value是否可调用...

function ensure_default(&$var, $default_value)
{
    if (! $var) {
        $var = (is_callable($default_value))?$default_value():$default_value;
    }
}

哪个允许...

$var1 = 'some_value';   // Values used for testing
$var1 = null;

ensure_default($var1, 'default_value1');
print_r($var);

将默认值设置为字符串(或实际上大多数其他值)。

答案 2 :(得分:0)

为什么不$var = 'some_value' || resource_intensive_lookup()?我想'some_value'在现实世界中将是一个变量,但是我认为代码片段抓住了这个想法。