3

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

我有一个加载文档的功能。如果该文档不存在,它将创建它,如果它确实存在,则将其转换为 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
}

现在,上面的代码没有任何问题(至少我认为没有问题,并且工作正常)。然而,我一直在寻找改进我的代码并在保持其清晰易读的同时对其进行压缩的方法。而那个 return 语句一直困扰着我,因为它看起来效率很低。所以今天我开始思考并且发生了一些事情。我记得看到 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();
}

似乎,它甚至读起来也足够令人愉快。继续我的下一轮问题。这是好习惯吗?我明白,但其他人会吗?它真的有效吗,或者这是一个快乐结局的错误?我环顾四周,发现我要问的是所谓的短路评估,而不是错误。很高兴知道。我使用这个新术语来优化我的搜索并想出了更多的材料。

博客条目

维基百科

我发现的几乎所有内容都没有提到以我询问的方式使用短路的方式总是提到 MySQL 连接。现在,我知道大多数人反对使用该or die()术语,但这仅仅是因为它是一种处理错误的不雅方式。对于我要询问的方法来说,这不是问题,因为我不想使用or die(). 还有其他理由不使用它吗?Wikipedia 似乎是这样认为的,但仅参考 C。我知道 PHP 是用 C 编写的,因此这绝对是相关信息。但是这个问题在 PHP 编译中已经被淘汰了吗?如果不是,它是否像维基百科所说的那样糟糕?

这是来自维基百科的片段。

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

大家怎么看?

编辑

我已经调查了另一个论坛并在那里得到了一些不错的结果。普遍的共识似乎是这种形式的变量赋值虽然有效,但不是首选,在现实世界中甚至可能被认为是不好的形式。我会继续关注地面,如果有任何新情况出现,我会更新。感谢 Corbin 和 Matt 的意见,特别是 Corbin 澄清了一些事情。如果您有兴趣,这里是论坛帖子的链接。

4

3 回答 3

2

你问了几个不同的问题,所以我会尽力解决所有问题。

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

还有其他理由不使用它吗?Wikipedia 似乎是这样认为的,但仅参考 C。我知道 PHP 是用 C 编写的,因此这绝对是相关信息。

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

至于格式,我觉得$a or $b很丑。我的头脑并不理解它在 if 子句中看到的短路。

if (a() || b())

我非常清楚 b() 只有在 a() 不评估为真时才会执行。

然而:

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();

}

我想这些代码片段真的归结为个人喜好。第二个片段可能是我要使用的片段。其中的关键路径可能会更清晰一些,但我觉得它在不牺牲可理解性的情况下保持简洁。

编辑:如果您是每个函数返回 1 的人,则以下可能更可取:

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;

}
于 2012-05-08T21:52:59.443 回答
1

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

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

于 2012-05-08T21:53:16.033 回答
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];

但令我惊讶的是,当 $data 中不存在 $key 时,PHP 没有抛出任何错误。

于 2014-09-04T09:19:40.837 回答