PHP短路评估(好/坏?)

时间:2012-05-08 21:39:46

标签: php short-circuiting

这是一个普遍的问题,但为了解释它,我将使用一个具体的例子。

我有一个加载文档的函数。如果该文档不存在,它将创建它,如果它确实存在,它将把它转换为JSON数组。我总是希望这个函数返回某种数组,无论json_decode()是否存在问题,或者该文件是否存在。目前我这样做......

function load($file) {
    if( ! file_exists($file)) {
        $handle = fopen($file, 'w');
        fclose($handle);
    }

    $raw = file_get_contents($file);
    $contents = json_decode($raw, TRUE);

    return( ! $contents ? array() : $contents);
    //cant use ternary shorthand "?:" in PHP 5.2, otherwise this would be shorter
}

现在,上面的代码没有任何问题(至少我认为没有,它工作正常)。但是,我一直在寻找改进代码的方法,并在保持代码清晰易读的同时对其进行压缩。这种回报声一直困扰着我,因为它似乎效率低下。所以今天我开始思考并且发生了一些事情。我记得看到mysql教程对connect() or die();的效果做了些什么,所以我想,为什么不json_decode() or array();?这甚至会起作用吗?所以我重写了我的功能以找出...

function load($file) {
    if( ! file_exists($file)) {
        $handle = fopen($file, 'w');
        fclose($handle);
    }

    $raw = file_get_contents($file);
    return json_decode($raw, TRUE) or array();
}

似乎,它甚至可以读得愉快。接下来我的下一回答。这是好习惯吗?我明白了,但还有其他人吗?这真的有用吗?或者这是一个快乐结局的错误?我到处寻找并发现我所询问的是短路评估而不是错误。很高兴知道。我使用这个新术语来改进我的搜索并提出了更多的材料。

Blog Entry

Wikipedia

在我询问的方式中,我发现并没有太多和我讨论过使用短路的所有内容总是被称为MySQL连接。现在,我知道大多数人反对使用or die()术语,但这只是因为它是一种处理错误的不雅方式。这不是我要问的方法的问题,因为我不想使用or die()。有没有其他理由不使用它?维基百科似乎这么认为,但只是参考C.我知道PHP是用C语言编写的,所以这绝对是相关的信息。但是这个问题在PHP编译中被忽略了吗?如果没有,它是否像维基百科那样糟糕?

这是维基百科的片段。

维基百科 - “短路可能会导致现代处理器上的分支预测错误,并显着降低性能(一个值得注意的例子是光线跟踪中具有轴对齐框交叉代码的高度优化光线)[需要澄清]。一些编译器可以检测到这种情况并发出更快的代码,但由于可能违反C标准,并不总是可行的。高度优化的代码应该使用其他方法来实现这一点(如手动使用汇编代码)“< / p>

你们都在想什么?

修改

我已经对另一个论坛进行了调查,并在那里取得了一些好成绩。普遍的共识似乎是这种形式的变量赋值虽然有效,但并不是优选的,在现实世界中甚至可能被视为不良形式。如果有任何新的问题,我会继续保持警惕,并对此进行更新。感谢Corbin和Matt的意见,特别是Corbin清理了一些东西。 Here如果您有兴趣,可以链接到论坛帖子。

3 个答案:

答案 0 :(得分:2)

你提出了几个不同的问题,所以我会尽力解决这些问题。

错过分支预测:除非您使用C或汇编编码,否则不要担心。在PHP中,你离硬件太远了,考虑分支预测不会对你有所帮助。无论哪种方式,这将是一个非常微观的优化,尤其是在开始广泛的字符串解析的函数中。

  

还有其他原因不使用此功能吗?维基百科似乎这么认为,但只是参考C.我知道PHP是用C语言编写的,所以这绝对是相关的信息。

PHP可能会将其解析为不同的执行结构。除非你计划运行这个功能数百万次,否则你知道这是一个瓶颈,我不担心。在2012年,我发现使用or短路不太可能导致甚至十亿分之一秒的差异。

至于格式化,我发现$a or $b相当难看。我的思想并不理解它在if子句中看到的短路。

if (a() || b())

我完全清楚b()只有在()没有评估为真时才会执行。

然而:

return a() or b();

对我来说没有同样的清晰度。

这显然只是一个意见,但我会提供两种选择,我可以如何写它(在我看来,这是一个非常小的清晰):

function load($file) {
    if (!file_exists($file)) {
        touch($file);
        return array();
    }

    $raw = file_get_contents($file);

    $contents = json_decode($raw, true);

    if (is_array($contents)) {
        return $contents;
    } else {
        return array();
    }

}

如果你不关心文件是否真的被创建了,你可以更进一步:

function load($file) {

    $raw = file_get_contents($file);

    if ($raw !== false) {
        $contents = json_decode($raw, true);
        if ($contents !== null) {
            return $contents;
        }
    }

    return array();

}

我猜这些代码片段确实归结为个人偏好。第二个片段很可能就是我要去的那个片段。关键路径可能会更加清晰,但我觉得它在不牺牲可理解性的情况下保持简洁。

编辑:如果你是一个每个函数返回一次的人,那么以下可能会更优选:

function load($file) {

    $contents = array();

    $raw = file_get_contents($file);

    if ($raw !== false) {
        $contents = json_decode($raw, true);
        if ($contents === null) {
            $contents = array();
        }
    }

    return $contents;

}

答案 1 :(得分:1)

将代码压缩到简约线条中你可以得到它并不总是最好的方法,因为通常压缩代码看起来很酷,但通常很难阅读。如果您对代码和可读性有任何疑问,我建议您在代码中添加一些标准注释,以便任何人都能从您的评论中理解代码。

就最佳实践而言,这是一个意见问题,如果您对此感到满意,那么请继续使用它,如果需要,您可以随后在项目生命周期中重新访问代码

答案 2 :(得分:0)

我确实喜欢短路声明,因为这是一种进行单行变量检查的方法。

我更喜欢:

isset($value) or $value = 0;

而不是:

if (!isset($value)) {
  $value = 0;
}

但是我没有直接在回报中使用它,这篇文章想要尝试。

可悲的是,它不能正常工作,至少对我而言:

return $data[$key] or $data[1];

在所有情况下都会返回值1,而我期待一个数组。

以下工作顺利进行:

// Make sure $key is valid.
$data[$key] or $key = 1;

return $data[$key];

但我很惊讶当$ key中没有$ key时,PHP没有抛出任何错误。