同事已经在我们的库中添加了几次assert命令,在那里我将使用if语句并抛出异常.(在此之前我从未听说过断言.)以下是他如何使用它的一个例子:
assert('isset($this->records); /* Records must be set before this is called. */');
Run Code Online (Sandbox Code Playgroud)
我会做的:
if (!isset($this->records)) {
throw new Exception('Records must be set before this is called');
}
Run Code Online (Sandbox Code Playgroud)
通过在assert上阅读PHP文档,看起来建议您确保assert处于活动状态并在使用assert之前添加处理程序.我找不到他这样做的地方.
所以,我的问题是,鉴于上述情况,使用断言是一个好主意,我应该更频繁地使用它而不是if和例外吗?
另外,我们计划在各种项目和服务器上使用这些库,包括我们甚至可能不参与的项目(库是开源的).这在使用assert时有什么不同吗?
aar*_*ing 77
适用于大多数语言的经验法则(我隐约知道)是a assert用于断言条件总是正确的,而if如果可以想象它有时会失败则适用.
在这种情况下,我认为这assert是合适的(基于我对情况的微弱理解)因为records应该始终在调用给定方法之前设置.因此,未能设置记录将是程序中的错误而不是运行时条件.在这里,assert有助于确保(通过适当的测试)没有可能的程序执行路径可能导致被保护的代码assert被调用而没有records被设置.
与使用assert相反的优点if是assert通常可以在生产代码中关闭,从而减少开销.最好处理的那种情况if可能会在生产系统的运行时期间发生,因此不会因为无法将其关闭而丢失.
Dav*_*ley 25
将断言视为"权力评论".而不是像这样的评论:
// Note to developers: the parameter "a" should always be a number!!!
Run Code Online (Sandbox Code Playgroud)
使用:
assert('is_numeric(a) /* The parameter "a" should always be a number. */');
Run Code Online (Sandbox Code Playgroud)
含义完全相同,适用于完全相同的受众,但第一个注释很容易被遗忘或忽略(无论感叹号多少),而"权力评论"不仅可供人类阅读和理解,它在开发过程中也经常进行机器测试,如果您在代码和工作习惯中设置良好的断言处理,则不会被忽略.
从这个角度看,断言是一个完全不同的概念,而不是if(错误)......和异常,它们可以共存.
是的,你应该评论你的代码,是的,你应该尽可能使用"权力评论"(断言).
mar*_*rio 16
这完全取决于您的发展战略.大多数开发人员都不知道assert()并使用下游单元测试.但主动和内置测试方案有时可能是有利的.
assert很有用,因为它可以启用和禁用.如果没有定义这样的断言处理程序,它不会消耗性能.你的同事没有,你应该设计一些临时在开发环境中启用它的代码(如果E_NOTICE/E_WARNINGs打开,那么应该是断言处理程序).偶尔使用它我的代码不能使用混合变量类型 - 我通常不会在弱类型的PHP中进行严格的输入,但随机使用情况:
function xyz($a, $b) {
assert(is_string($a));
assert(is_array($b));
Run Code Online (Sandbox Code Playgroud)
例如,这将弥补类型说明符的不足string $a, array $b.PHP5.4将支持它们,但不检查.
关于PHP中早于7的assert的重要说明。与其他具有assert构造的语言不同,PHP不会完全抛出assert语句-它将其视为函数(在由断言调用的函数中执行debug_backtrace())。关闭断言似乎只是使函数热衷于在引擎中什么也不做。请注意,可以通过将zend.assertions设置为0而不是更普通的值1(on)或-1(off)来使PHP 7模仿此行为。
问题是断言将接受任何参数-但是,如果参数不是字符串,则断言无论断言是打开还是关闭都将获取表达式的结果。您可以使用以下代码块进行验证。
<?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.\')');
Run Code Online (Sandbox Code Playgroud)
鉴于assert的意图,这是一个错误,并且是一个长期存在的错误,因为它是从PHP 4中引入assert以来一直使用的语言。
评估传递给assert的字符串,以及随之而来的所有性能影响和危害,但这是使assert语句按PHP方式工作的唯一方法(此行为在PHP 7.2中已弃用)。
编辑:更改为注意PHP 7和7.2的更改
您的同事实际上正在尝试应用Eiffel 语言中的契约设计(DbC),并基于《面向对象软件构建》第二版一书。
\n\n正如他所使用的,该断言将是霍尔逻辑或霍尔三元组的 {P} 部分:{P} C {Q},其中 {P} 是前置条件断言(ion),{Q} 是后置条件断言(ion)。
\n\n我会认真对待有关 PHP 中断言功能存在错误的建议。您不想使用有错误的代码。你真正想要的是 PHP 的开发者修复断言中的错误。在他们这样做之前,您可以使用断言,但使用它时要注意其当前的错误状态。
\n\n此外,如果断言功能有错误,那么我建议您不要在生产代码中使用它。尽管如此,我还是建议您在适当的情况下在开发和测试代码中使用它。
\n\n最后\xe2\x80\x94如果你研究契约设计,你会发现根据面向对象的经典继承使用布尔断言会产生后果\xe2\x80\x94也就是说\xe2\x80\x94你必须永远不要削弱前提条件,也不要削弱后置条件。这样做可能会对彼此交互的多态后代对象造成危险。在你明白这意味着什么之前\xe2\x80\x94\我不会管它!
\n\n另外\xe2\x80\x94我强烈建议PHP的开发者对契约设计进行全面的研究,并尝试尽快将其移植到PHP中!那么我们所有人都可以从拥有 DbC 感知的编译器/解释器中受益,它将处理答案中指出的问题(上面):
\n\n注意:即使您使用if语句作为断言(前置条件)的替代品,如果用于加强前置条件或削弱后置条件,也会遭受可怕的后果。要理解这意味着什么,您需要研究合同设计才能知道!:-)
快乐的学习和学习。
\n| 归档时间: |
|
| 查看次数: |
24749 次 |
| 最近记录: |