Typechecker特殊情况
有时你可能想要告诉Typechecker是没报错的,继续运行。最常见的情况是当你知道有一个typechecker错误,你不会因为任何原因修复它,但你仍然希望你的代码在运行时清除typechecker错误hh_client...,你想No errors!输出。
有几种方法可以使typechecker沉默。有些人比其他人更注重行动。
HH_FIXME
HH_FIXME是您通常使用的消声器。这意味着临时缓解从typechecker错误的愤怒,所以您可以从类型检查器的角度维护一个无错误的代码库。
语法HH_FIXME是:
/ * HH_FIXME [error#] string comment * /
<code of code>
从运行时收到的实际错误消息中检索错误代码hh_client
。字符串注释可以是任何您想要的,但通常会解释为什么您正在使用HH_FIXME
开始。
<?hh // strict
namespace Hack\UserDocumentation\TypeChecker\Special\Examples\HHFixMe;
// This was the function before we went to strict mode and added annotations to
// to the annotating function. It was fine from the typechecker perspective.
/*
function annotating($x) {
return $x > 5 ? "Hello" : $x;
}
*/
function annotating(?string $x): string {
return $x === null ? "Hello" : "Bye";
}
function call_annotating(): void {
/* HH_FIXME[4110] Will make 6 to "6" later */
annotating(6);
}
function also_call_annotating(): void {
/* HH_FIXME[4110] Will make true to "true" later */
annotating(true);
}
/* HH_FIXME[1002] Will move this call to a partial file later */
call_annotating();
Output
Catchable fatal error: Argument 1 to Hack\UserDocumentation\TypeChecker\Special\Examples\HHFixMe\annotating() must be of type ?string, int given in /data/users/joelm/user-documentation/guides/hack/25-typechecker/07-special-examples/hhfixme.php on line 17
假设我们处于部分模式,现在我们要使这个文件严格,但是我们知道,调用站点将受到函数注释的影响,因为我们做了一些可疑的类型转换。我们不想修复它,或者我们不知道如何解决它(尽管你应该在运行时之前修复,因为它现在将是一个运行时错误)。因此,我们适用HH_FIXME于所有受到变更影响的电话网站,以便您或其他人知道他们需要修复。
没有HH_FIXME,你会看到像:
hhfixme.php:21:14,14: Invalid argument (Typing[4110])
hhfixme.php:15:22,27: This is a string
hhfixme.php:21:14,14: It is incompatible with an int
hhfixme.php:26:14,17: Invalid argument (Typing[4110])
hhfixme.php:15:22,27: This is a string
hhfixme.php:26:14,17: It is incompatible with a bool
hhfixme.php:29:1,15: Remove all toplevel statements except for requires (Parsing[1002])
在这个例子中,你也可以把HH_FIXME注释放在函数本身上,效果相同。但通常最好HH_FIXME放在最具体的块上。
注意:您可以HH_FIXME在单行代码上有多个注释,表示多个Hack错误的沉默。
HH_IGNORE_ERROR
HH_IGNORE_ERROR在技术上是一个别名HH_FIXME,但可以用来为任何看你的代码的人提供更好的环境。虽然,HH_FIXME表示将采取一些行动来解决Hack错误,您正在沉默(由于Hack类型检查程序或您的Hack代码中HH_IGNORE_ERROR的错误),指定您故意忽略该错误,并且不打算采取任何行动修复错误。
语法HH_IGNORE_ERROR是:
/* HH_IGNORE_ERROR[error #] string comment */
<block of code>
一个典型的用例HH_IGNORE_ERROR
是用于卷起。hh_client --lint
例如,如果您正在使用,则可以按照下面所示的方法来抑制短路错误。
<?hh
namespace Hack\UserDocumentation\Typechecker\Special\Examples\HHIE;
class A {
// Normally if you use hh_client --lint hh_ignore_error.php without
// the below HH_IGNORE_ERROR suppression comment, you will get a lint
// error about using the uppercase TRUE.
/* HH_IGNORE_ERROR[5001] We want to use uppercase TRUE */
private bool $a = TRUE;
}
UNSAFE
UNSAFE(或同义UNSAFE_BLOCK)也会使Typechecker沉默。但这不是一个被动作的沉默机制。当使用UNSAFE的时候,你基本上是说你知道这个代码块是个问题,而你就是这样离开的。
语法UNSAFE是:
// UNSAFE
<some block of code>
<?hh // strict
namespace Hack\UserDocumentation\TypeChecker\Special\Examples\Unsafe;
// This was the function before we went to strict mode and added annotations to
// to the annotating function. It was fine from the typechecker perspective.
/*
function annotating($x) {
return $x > 5 ? "Hello" : $x;
}
*/
function annotating(?string $x): string {
return $x === null ? "Hello" : "Bye";
}
function call_annotating(): void {
// UNSAFE
annotating(6);
}
function also_call_annotating(): void {
// UNSAFE
annotating(true);
}
/* HH_FIXME[1002] Will move this call to a partial file later */
call_annotating();
Output
Catchable fatal error: Argument 1 to Hack\UserDocumentation\TypeChecker\Special\Examples\Unsafe\annotating() must be of type ?string, int given in /data/users/joelm/user-documentation/guides/hack/25-typechecker/07-special-examples/unsafe.php on line 17
使用类似的例子HH_FIXME,我们用三个替换了两个UNSAFE。为什么不是第三个?那么,UNSAFE没有那么强大HH_FIXME。UNSAFE不能在顶级代码上使用。
尽量不要使用UNSAFE,而是选择HH_FIXME。UNSAFE不太详细和详细HH_FIXME,这可能会导致一个问题,任何人可能想尝试在以后解决问题。
注意:UNSAFE将来可能会被废弃或删除。所以所有新的沉默都应该完成HH_FIXME。
UNSAFE_EXPR
UNSAFE_EXPR类似于UNSAFE,除了在单个表达式而不是整个代码块上关闭类型检查器。
其语法UNSAFE_EXPR是:
/ * UNSAFE_EXPR * / <expression>
例如,
$ foo = / * UNSAFE_EXPR * / $ bar :: baz();
这是一个有点复杂的例子,显示了使用UNSAFE_EXPR。你可能不想在现实世界中做到这一点,但是希望能够直接得到希望。
<?hh
namespace Hack\UserDocumentation\Typechecker\Special\Examples\UnsafeExpr;
function foo(string $num): int {
// Without UNSAFE_EXPR, couldn't add stringy number to a number and then
// return that result later.
$x = /* UNSAFE_EXPR */ $num + 2;
echo "More statements here...\n";
return $x;
}
function run(): void {
var_dump(foo("1"));
}
run();
Output
More statements here...
int(3)
注意/* */风格评论而UNSAFE_EXPR不是//for UNSAFE。这是很重要的,因为// UNSAFE_EXPR将会被解析为// UNSAFE,并可能给您带来意想不到的结果。
这是一个关于动态属性访问的更真实的示例。在Hack的严格模式下,不允许动态访问属性。你可以UNSAFE_EXPR用来解决这个问题。
<?hh //strict
namespace Hack\UserDocumentation\Typechecker\Special\Examples\UnsafeDP;
class Ranking {
public function __construct(
protected int $first,
protected int $second,
protected int $third,
) {}
public function copyFields(Ranking $from): Ranking {
foreach (['first', 'second', 'third'] as $field) {
/* UNSAFE_EXPR */ $this->$field = $from->$field;
}
return $this;
}
}
/*
Without the UNSAFE_EXPR, you would get an error like this from the typechecker.
unsafe_expr_dynamic_prop.php:14:14,19: Dynamic method call (Naming[2011])
*/