hack高级规则
类型检查规则通常很简单(例如,不能传递string给期望的内容int)。然而,有一些规则有一些更高级的语义。
软类型提示
看看这个例子:
<?hh
namespace Hack\UserDocumentation\Types\AdvancedRules\Examples\SoftHint;
// HHVM will throw a warning instead of fatal if, for example, a bool is passed
// in
function foo(@int $x): bool {
return $x < 5 ? true : false;
}
function call_foo(): void {
foo(5);
foo(false);
}
call_foo();
Output
Warning: Argument 1 to Hack\UserDocumentation\Types\AdvancedRules\Examples\SoftHint\foo() must be of type @int, bool given in /data/users/joelm/user-documentation/guides/hack/20-types/08-advanced-rules-examples/softhint.php.type-errors on line 9
前面的“@”是什么意思?这导致HHVM在传递的参数不匹配时触发警告(因此始终继续执行)而不是可捕获的致命错误。它用于允许您慢慢添加类型到您的代码。
软类型提示对类型检查器行为没有影响。如果类型不匹配,类型检查器仍然会抛出错误。
Superglobals
无论你目前在什么范围内,Superglobals都可以使用。
<?hh
namespace Hack\UserDocumentation\Types\AdvancedRules\Examples\SuperGlobals;
function get_superglobal(string $s): array<string> {
// If you try to use a variable that doesn't exist (e.g., $_NOEXIST), the
// typechecker will thrown an undefined variable error.
switch ($s) {
case '_GET':
return $_GET;
break;
case '_ENV':
return $_ENV;
break;
case '_SERVER':
return $_SERVER;
break;
default: // not supporting anything else
return array();
}
}
function sg(string $s): array<string> {
return get_superglobal($s);
}
var_dump(is_array(sg('_SERVER')));
Output
bool(true)
类型检查器知道内置超帧。
在Hack的严格模式下,superglobals不支持。所以你必须创建一些类似部分模式的功能,以从严格的模式文件中调用。
可以使用将PSR-7暴露给Hack 的存储库来实现使用superglobals的不完美但可行的替代方案。这个repo中的HHI文件给出了关于接口的Hack类型检查器信息。
可变参数
Hack支持可变参数:
function foo(<any explicit arguments>, int ...$args) // $args is a list of int arguments
类型检查器将强制执行可变类型,但是对于性能,运行时不会。
<?hh
namespace Hack\UserDocumentation\Types\AdvancedRules\Examples\Variadic;
function foo(int ...$args): vec<int> {
$ret = vec[];
foreach ($args as $arg) {
$ret[] = $arg;
}
return $ret;
}
function bar(): void {
var_dump(foo(1, 2, 3, 4));
}
bar();
Output
vec(4){
int(1)
int(2)
int(3)
int(4)
}
Fallthrough
switch言论中无意的跌倒是一个常见的错误。黑客提供了一种抓住突破的方法,增加了一种告诉它这是有意的方法。
<?hh
namespace Hack\UserDocumentation\Types\AdvancedRules\Examples\Fallthrough;
function fallthrough(int $x): void {
switch ($x) {
case 1: echo "1"; break; // without the break, typechecker throws an error
case 2: echo "2"; break;
case 3: echo "3"; break;
case 4: echo "4"; // but we can tell the typechecker we want it
// FALLTHROUGH
default: echo "5";
}
}
fallthrough(4);
Output
45
使用// FALLTHROUGH
要告诉我们的是通过故意落在typechecker。
类属性初始化
Hack需要将类属性在使用之前初始化为其适当注释类型的值。
- 必须使用值初始化所有不可为空的静态类属性。
- 默认情况下,没有初始值的Nullable 静态类属性具有null值。
- 必须在构造函数中初始化所有不可为空的非静态类属性。
- 默认情况下,未在构造函数中初始化的Nullable 非静态类属性将具有null值。
- 在构造函数中初始化其属性之前,您不能在类上调用公共或私有实例方法。
- 在构造函数中初始化属性之前,您可以调用私有实例方法,只要属性在访问该属性之前在该私有调用链的某处初始化即可。
方法继承
父类定义一个方法,其子类覆盖它。这很常见 Hack有一些关于重写方法必须遵循的方法的规则。
- 任何重写方法的参数都必须匹配参数计数和每个参数上的类型。
- 覆盖方法的返回类型可能具有比其父代更具体的类型; 当然,它们必须是兼容的(例如,arraykey在父母中,string在孩子中)。