【问题标题】:Is it possible to tell the php interpreter to ignore code blocks?是否可以告诉 php 解释器忽略代码块?
【发布时间】:2015-08-19 13:42:45
【问题描述】:

背景

在我进行 C 编程的那一天,我们使用假设语句来确保代码是健康的。比如:

aFunction(int hello)
{
  assume(hello < 10);

假设语句很酷的一点是它被定义为一个用于发布编译的空宏和一个用于调试编译的错误语句。因此,开发人员拥有断言语句检查他们的假设的所有好处,而不会导致不必要的错误或影响性能

问题

现在我正在使用 php,我正在寻找类似的机制。我目前的假设语句看起来像这样:

define(DEBUG, getenv('debug'));
function assume($a)
{
  if (DEBUG && !$a)
  {
    echo 'ASSUME FAILURE <br />';
    echo '<pre>';
    print_r(debug_backtrace());
    die('<pre>');
  }
}
assume($a == $b);

如您所见,我在服务器设置中设置了调试标志以删除实际的 die 语句等。但是,仍会执行函数调用,并且仍会评估 if 语句。如果它只发生几千次,这没什么大不了的,但是随着代码变得越来越大并且这些假设被放入循环中,这可能会对性能产生合理的影响。

问题

有没有办法告诉解释器或 opcache(我目前正在使用 php 5.5 中包含的 zend opcache)完全忽略这些假设语句?还是有其他方法可以解决这个问题?

【问题讨论】:

  • 简短回答。保持单元测试与实际代码相邻,而不是混入其中。它使事情变得混乱并增加了开销。当然,您可以将其作为某些 CI 过程的一部分进行清理。但是,有测试和 PHP 的最佳实践,请遵循它们。
  • 你熟悉 PHPUnit 吗?如今,使用验证代码各个方面的测试套件确实会更好地处理这件事,而不是您的代码自我验证phpunit.de
  • @MichaelBerkowski 单元测试与假设语句是一个非常不同的用例。我很想有朝一日进行一些单元测试,但它并不能取代一个简单的假设。
  • PHP 更多的是关于“运行时”,因为在任何一天,它都可以变得非常“动态”。但是,没有什么可以阻止您使用:assert — Checks if assertion is FALSE,在您希望的任何地方进行“健全性”检查。它们可能非常有用。

标签: php interpreter opcache


【解决方案1】:

不同之处在于 C 编译器经过优化,可以消除不使用的代码块。在PHP中,assume是函数调用,函数必须存在。

几个解决方案。首先,您可以使用assert()。 assert 函数的工作方式类似于您自己的 assume 函数。如果断言失败,则调用定义的断言处理程序。您可以轻松启用或禁用断言,如果禁用它们,则根本不会调用断言处理程序。

如果你想继续使用你自己的assume函数,你仍然可以稍微优化一下,通过基于define声明函数:

<?php
define(DEBUG, getenv('debug'));

if (DEBUG) {
  function assume($a) {
    echo 'ASSUME FAILURE <br />';
    echo '<pre>';
    echo print_r(debug_backtrace());
    die('<pre>');
  }
} else {
  function assume($x) {}
}

这样,您实际上将assume 声明为一个空函数。 Michael Berkowski 的评论证实了我担心 PHP 并没有完全消除调用,但至少你保存了 if。

另一种解决方案是调用更复杂一点的假设:

DEBUG && assume($x < 10);

这样,如果 DEBUG 为 false,则根本不会进行调用。这种方式只计算布尔值,不进行函数调用。当然,以这种方式调用它有点难,可读性也较差,但我认为不调用函数所节省的成本比消除if 要重要得多。

【讨论】:

  • 看起来 PHP 并没有使空函数定义无效,在这个测试中,它的运行速度比无操作慢 2-3 倍。不过,这是一个很酷的解决方案。 3v4l.org/7XQMV
  • 我认为断言符合我的要求。我没有意识到它可以配置为不执行。
  • 就DEBUG &amp;&amp; assume($x &lt; 10)方法而言,在5.6之后如果您启用了OPcache优化器,那么这将进行常量折叠并且将消除if (FALSE)类型表达式,只要常量是在编译时定义的(即在以前编译的模块中)。
猜你喜欢
  • 1970-01-01
  • 2011-01-18
  • 1970-01-01
  • 2018-07-21
  • 1970-01-01
  • 2014-03-11
  • 1970-01-01
  • 2016-08-10
  • 2022-08-19
相关资源
最近更新 更多