我应该在我的 PHP 代码中使用断言吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4516419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 13:16:20  来源:igfitidea点击:

Should I be using assert in my PHP code?

phpassert

提问by Darryl Hein

A coworker has added the assertcommand a few times within our libraries in places where I would have used an if statement and thrown an exception. (I had never even heard of assert before this.) Here is an example of how he used it:

一位同事在我们的库中多次添加了assert命令,在这些地方我会使用 if 语句并抛出异常。(在此之前我什至从未听说过 assert。)这是他如何使用它的一个例子:

assert('isset($this->records); /* Records must be set before this is called. */');

I would have done:

我会这样做:

if (!isset($this->records)) {
    throw new Exception('Records must be set before this is called');
}

From reading the PHP docs on assert, it looks like it's recommended that you make sure assert is active and add a handler before using assert. I can't find a place where he's done this.

从阅读有关 assert 的 PHP 文档来看,似乎建议您确保 assert 处于活动状态并在使用 assert 之前添加处理程序。我找不到他这样做的地方。

So, my question is, is using assert a good idea given the above and should I be using it more often instead of if's and exceptions?

所以,我的问题是,鉴于上述情况,使用断言是一个好主意,我应该更频繁地使用它而不是 if 和异常吗?

Another note, we are planning to use these libraries on a variety of projects and servers, including projects that we may not even be part of (the libraries are open source). Does this make any difference in using assert?

另请注意,我们计划在各种项目和服务器上使用这些库,包括我们甚至可能不参与的项目(这些库是开源的)。这对使用断言有什么影响吗?

采纳答案by aaronasterling

The rule of thumb which is applicable across most languages (all that I vaguely know) is that an assertis used to assert that a condition is alwaystrue whereas an ifis appropriate if it is conceivable that it will sometimes fail.

适用于大多数语言的经验法则(我所知道的一切)是 anassert用于断言条件始终为真,而 anif是合适的,如果可以想象它有时会失败。

In this case, I would say that assertis appropriate (based on my weak understanding of the situation) because recordsshould alwaysbe set before the given method is called. So a failure to set the record would be a bug in the program rather than a runtime condition. Here, the assertis helping to ensure (with adequate testing) that there is no possible program execution path that could cause the code that is being guarded with the assertto be called without recordshaving been set.

在这种情况下,我会说这assert是合适的(基于我对情况的薄弱理解),因为records应该始终在调用给定方法之前设置。因此,未能设置记录将是程序中的错误,而不是运行时条件。在这里,assert帮助确保(通过充分测试)没有可能的程序执行路径可能导致被保护的代码在没有设置的assert情况下被调用records

The advantage of using assertas opposed to ifis that assertcan generally be turned off in production code thus reducing overhead. The sort of situations that are best handled with ifcould conceivably occur during runtime in production system and so nothing is lost by not being able to turn them off.

的使用的优点assert,而不是ifassert通常可在这样的生产代码减少开销被关闭。if可以想象,在生产系统的运行时期间可能会发生最好处理的那种情况,因此无法关闭它们不会有任何损失。

回答by DaveWalley

Think of asserts as "power comments". Rather than a comment like:

将断言视为“强力评论”。而不是像这样的评论:

// Note to developers: the parameter "a" should always be a number!!!

use:

用:

assert('is_numeric(a) /* The parameter "a" should always be a number. */');

The meanings are exactly the same and are intended for the exact same audience, but the first comment is easily forgotten or ignored (no matter how many exclamation marks), while the "power comment" is not only available for humans to read and understand, it is also constantly machine-tested during development, and won't be ignored if you set up good assert handling in code and in work habits.

意思完全一样,面向完全相同的受众,但第一条评论很容易被遗忘或忽略(无论有多少感叹号),而“强力评论”不仅可供人类阅读和理解,它也在开发过程中不断进行机器测试,如果您在代码和工作习惯中设置了良好的断言处理,它也不会被忽略。

Seen this way, asserts are a completely different concept than if(error)... and exceptions, and they can co-exist.

从这个角度来看,断言是一个与 if(error)... 和异常完全不同的概念,它们可以共存。

Yes, you should be commenting your code, and yes, you should be using "power comments" (asserts) whenever possible.

是的,您应该注释您的代码,是的,您应该尽可能使用“强力注释”(断言)。

回答by mario

It wholly depends on your development strategy. Most developers are unaware of assert()and use downstream unit testing. But proactive and built-in testing schemes can sometimes be advantageous.

这完全取决于您的发展战略。大多数开发人员不知道assert()并使用下游单元测试。但主动和内置的测试方案有时可能是有利的。

assert is useful, because it can be enabled and disabled. It doesn't drain performance if no such assertion handler is defined. Your collegue doesn't have one, and you should devise some code which temporary enables it in the development environment (if E_NOTICE/E_WARNINGs are on, so should be the assertion handler). I use it occasionally where my code can't stomach mixed variable types - I don't normally engage in strict typing in a weakly typed PHP, but there random use cases:

assert 很有用,因为它可以启用和禁用。如果没有定义这样的断言处理程序,它不会降低性能。你的同事没有,你应该设计一些在开发环境中临时启用它的代码(如果 E_NOTICE/E_WARNINGs 开启,那么断言处理程序也应该开启)。我偶尔会在我的代码无法忍受混合变量类型的情况下使用它 - 我通常不会在弱类型的 PHP 中进行严格的输入,但有随机用例:

 function xyz($a, $b) {
     assert(is_string($a));
     assert(is_array($b));

Which for example would compensate for the lack of type specifiers string $a, array $b. PHP5.4 will support them, but not check.

例如,这将弥补类型说明符的缺乏string $a, array $b。PHP5.4 会支持它们,但不会检查。

回答by Mark Snidovich

Assert is not a substitute for normal flow control like ifor exceptions, because it is only meant to be used for debugging during development.

Assert 不能替代正常的流程控制,如if或异常,因为它仅用于开发期间的调试。

回答by Michael Morris

An important note concerning assert in PHP earlier than 7. Unlike other languages with an assert construct, PHP doesn't throw assert statements out entirely - it treats it as a function (do a debug_backtrace() in a function called by an assertion). Turning asserts off seems to just hotwire the function into doing nothing in the engine. Note that PHP 7 can be made to emulate this behavior by setting zend.assertions to 0 instead of the more normal values of 1 (on) or -1 (off).

关于早于 7 的 PHP 中的断言的重要说明。与具有断言结构的其他语言不同,PHP 不会完全抛出断言语句 - 它将其视为一个函数(在由断言调用的函数中执行 debug_backtrace())。关闭断言似乎只是将功能热线连接到引擎中不执行任何操作。请注意,PHP 7 可以通过将 zend.assertions 设置为 0 而不是更正常的值 1 (on) 或 -1 (off) 来模拟这种行为。

The problem arises in that assert will take any argument - but if the argument is not a string then assert gets the results of the expression whether assert is on or off. You can verify this with the following code block.

问题在于 assert 将接受任何参数 - 但如果参数不是字符串,那么无论 assert 是打开还是关闭,assert 都会获取表达式的结果。您可以使用以下代码块验证这一点。

<?php
  function foo($a) { 
    echo $a . "\n"; 
    return TRUE;
  }
  assert_options(ASSERT_ACTIVE, FALSE);

  assert( foo('You will see me.'));
  assert('foo(\'You will not see me.\')');

  assert_options(ASSERT_ACTIVE, TRUE);

  assert( foo('Now you will see'));
  assert('foo(\'both of us.\')');

Given the intent of assert this is a bug, and a long standing one since it's been in the language since assert was introduced back in PHP 4.

鉴于断言的意图,这是一个错误,并且自从断言在 PHP 4 中引入以来它就一直存在于语言中。

Strings passed to assert are eval'ed, with all the performance implications and hazards that come with that, but it is the only way to get assert statements to work the way they should in PHP (This behavior deprecated in PHP 7.2).

传递给 assert 的字符串经过评估,伴随着所有的性能影响和危险,但它是让 assert 语句按照它们在 PHP 中应有的方式工作的唯一方法(这种行为在 PHP 7.2 中已弃用)。

EDIT: Changed above to note changes in PHP 7 and 7.2

编辑:以上更改以注意 PHP 7 和 7.2 中的更改

回答by Kyle

Assert should only be used in development as it is useful for debugging. So if you want you can use them for developing your website, but you should use exceptions for a live website.

断言应该只在开发中使用,因为它对调试很有用。因此,如果您愿意,您可以使用它们来开发您的网站,但您应该为实时网站使用例外。

回答by Larry

You coworker is really attempting to apply design by contract(DbC) from the Eiffel language and based on the book: Object Oriented Software Construction, 2nd Edition.

您的同事实际上是在尝试应用Eiffel 语言中的契约式设计(DbC),并基于这本书:面向对象的软件构造,第 2 版。

The assertion, as he used it, would be the {P}-part of the Hoare Logic or Hoare Triple: {P} C {Q}, where the {P} is the precondition assert(ion)s and {Q} are the post-condition assert(ion)s.

他使用的断言将是霍尔逻辑或霍尔三元组的 {P} 部分:{P} C {Q},其中 {P} 是前提断言(离子),{Q} 是后置条件断言(离子)。

I would take critical note of advice given about the assert feature in PHP having bugs. You don't want to use buggy code. What you really want are the makers of PHP to fix the bug in the assert. Until they do, you can use the assert, but use it mindful of its present buggy state.

我会认真注意有关 PHP 中存在错误的断言功能的建议。您不想使用有缺陷的代码。您真正想要的是 PHP 的制造商来修复断言中的错误。在他们这样做之前,您可以使用断言,但要注意其当前的错误状态。

Moreover, if the assert feature is buggy, then I suggest you do not use it in production code. Nevertheless, I do recommend that you use it in development and testing code where appropriate.

此外,如果断言功能有问题,那么我建议您不要在生产代码中使用它。尽管如此,我还是建议您在适当的情况下在开发和测试代码中使用它。

Finally—if you do a study of design by contract, you will find that there are consequences to using Boolean assertions in light of object-oriented classical inheritance—that is—you must must never weaken a precondition, nor weaken a post-condition. Doing so could be dangerous to your polymorphic descendant objects interacting with each other. Until you understand what that means—I'd leave it alone!

最后——如果你对契约式设计进行研究,你会发现根据面向对象的经典继承使用布尔断言会产生一些后果——也就是说——你绝不能弱化前置条件,也不能弱化后置条件。这样做可能会对相互交互的多态后代对象造成危险。直到你明白这意味着什么——我不会管它!

Moreover—I highly recommend that the makers of PHP do a comprehensive study of design by contract and attempt to put it into PHP ASAP! Then all of us can benefit from having a DbC-aware compiler/interpreter, which would handle the issues noted in the answers (above):

而且——我强烈建议PHP的开发者对契约式设计做一个全面的研究,并尽快把它放到PHP中!然后我们所有人都可以从拥有 DbC 感知编译器/解释器中受益,它可以处理答案(以上)中提到的问题:

  1. A properly implemented design-by-contract-aware compiler would (hopefully) be bug-free (unlike the current PHP assert).
  2. A properly implemented design-by-contract-aware compiler would handle the nuances of polymorphic assertion logic management for you instead of racking your brain over the matter!
  1. 一个正确实现的按合同设计的编译器将(希望)没有错误(与当前的 PHP 断言不同)。
  2. 一个正确实现的基于合同的设计编译器会为您处理多态断言逻辑管理的细微差别,而不是让您绞尽脑汁!

NOTE: Even your use of an if-statement as a substitute for the assert (precondition) will suffer dire consequences if used to strengthen a precondition or weaken a post-condition. To understand what that means, you will need to study design by contract to know! :-)

注意:如果使用 -if语句代替断言(前提条件),如果用于加强前提条件或削弱后置条件,也会遭受可怕的后果。要了解这意味着什么,您需要学习合同设计才能知道!:-)

Happy studying and learning.

快乐学习和学习。

回答by Dean Or

No, your co-worker shouldn't be using it as a general purpose error handler. According to the manual:

不,您的同事不应将其用作通用错误处理程序。根据手册:

Assertions should be used as a debugging feature only. You may use them for sanity-checks that test for conditions that should always be TRUE and that indicate some programming errors if not or to check for the presence of certain features like extension functions or certain system limits and features.

Assertions should not be used for normal runtime operations like input parameter checks. As a rule of thumb your code should always be able to work correctly if assertion checking is not activated.

断言应仅用作调试功能。您可以将它们用于完整性检查,以测试应始终为 TRUE 的条件,如果不是,则指示一些编程错误,或者检查某些功能的存在,如扩展功能或某些系统限制和功能。

断言不应用于正常的运行时操作,如输入参数检查。根据经验,如果未激活断言检查,您的代码应该始终能够正常工作。

If you are familiar with automated test suites, the "assert" verb is generally used to verify the output of some method or function. For example:

如果您熟悉自动化测试套件,那么“assert”动词通常用于验证某些方法或函数的输出。例如:

function add($a, $b) {
    return $a + $b;
}

assert(add(2,2) == 5, 'Two and two is four, dummy!');
assert(is_numeric(add(2,2)), 'Output of this function to only return numeric values.');

Your co-worker shouldn't be using it as a general purpose error handler and in this case as an input check. It looks like it's possible for the records field to not be set by some user of your library.

您的同事不应将其用作通用错误处理程序,在这种情况下不应将其用作输入检查。看起来您图书馆的某些用户可能没有设置记录字段。