本节书摘来自华章出版社《Hack与HHVM权威指南》一书中的第1章,第1.4.1节,作者 Owen Yamauchi,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1.4.1 类型检查器模式
Hack的类型检查器有三种模式:严格(strict)、局部(partial)和耦合(decl)。这些模式都基于一个个单独的文件,不同模式下的单独文件可以无缝地进行对接。每个文件可以单独声明它的类型检查模式,语法就是在文件的第一行使用一个双斜线的注释。如下面的代码所示:
<?hh // strict
如果文件的第一行没有上述类似的注释信息(比如第一行就是一个<?hh),将默认使用局部模式。
这三种模式间有很多的不同之处,通过对这些差异点的学习,我们可以了解类型检查器的很多特性。下面是对每种模式的具体说明。
严格模式: <?hh // strict
严格模式最重要的特性就是,所有命名的函数(以及方法)都必须有返回类型和参数类型标注,所有的属性也必须进行类型标注。换句话说,任何可能出现类型标注的地方都必须进行标注。但是有如下例外:
闭包不需要对参数类型和返回类型进行标注。
构造函数和析构函数不需要返回类型标注,非要让它们返回些什么也说不通。
在严格模式下有三条主要的限制:
使用任何在Hack文件中没有定义过的命名实体注2都会引发错误。这就是说,严格模式下的Hack代码无法调用PHP代码。但是严格模式下面的Hack代码可以调用局部模式或者耦合模式的Hack代码。
顶层文件中的大多数代码将会导致错误。require系列语句是允许的注3,因为它们用于定义命名实体注4。
使用引用赋值(比如$a=&$b),或者定义了“通过引用返回值或者引用接收参数”的函数或方法,都会引发错误。
还有一些其他更小的不同点,我们将会进行补充。
为了充分利用类型检查器的便利性,我们应该致力于尽可能地写严格模式的Hack代码。严格模式的Hack是个健全的系统,这就意味着,如果你的代码100%是在严格模式,那么你在代码运行时绝无可能引发类型错误的。这是一个非常强大的保证,你越接近这点越好。
局部模式: <?hh
局部模式放宽了严格模式的种种限制,它可以做它能够做的任何类型检查,但是它不要求代码里面必须写所有的类型标注。此外,
如果你正在使用函数或者类,类型检查器不能在Hack文件中发现的话,这并不会引发错误。类型检查器会宽大地认为这些丢失的实体都定义在一个PHP文件中,具体可以查看1.4.3节的内容。
顶层代码是允许的,但是不会检查类型。所以为了最小化不执行类型检查的代码数量,在理想的情况下,你应该把所有的顶层代码包装进某个函数,然后在你唯一的顶层代码语句中调用上述函数。下面是个相关的例子,最好不要这样做:
<?hh
set_up_autoloading(); do_logging();
$c = find_controller(); $c->go();
而改为这样做:
<?hh
function main() {
set_up_autoloading();
do_logging();
$c = find_controller();
$c->go();
}
main();
更好的做法是把main函数的定义放到一个严格模式的文件中。
引用是允许的,但是类型检查器本质上假装引用的相关代码不存在,并不会试图去规范它们的行为。在本例中,代码的最后一行后面类型检查器仍然会认为$a是个整型,尽管事实上它是一个字符串类型。
$a = 10;
$b = &$a;
$b = 'not an int';
简单来说,可以在局部模式下使用引用,但是这破坏了类型安全,所以你应该尽量避免使用它们。
甚至对于一个从头开始建立的新Hack项目来说,这里仍然有局部模式的文件需求。在任何的脚本或者Web应用中,总是需要有一定数量的顶层代码的存在,它们将作为入口点代码存在。所以你将至少需要一个局部模式的Hack文件。你需要使用局部模式来获得超级全局变量,比如$_GET、$_POST和$argv,我们将在1.5.1节对此展开更详细的阐述。
耦合模式: <?hh // decl
在耦合模式中,代码是不会被检查类型的。类型检查器做的所有事情就是读取和检索所有的函数签名以及定义在文件中的类。(在耦合模式下仍然会触发错误,比如无效的类型标注语法。)
耦合模式存在的目的在于,当迁移一个已经存在的PHP代码库到Hack代码时,提供一个过渡的功能。它为PHP和其他Hack代码模式提供了过渡的垫脚石。转化一个PHP文件到耦合模式的Hack文件是非常容易的,并且相对于保留为PHP文件而言,也具有显著的益处。首先,关于调用PHP代码的类型检查非常宽松。 (可以参见1.4.3节), 但是如果调用耦合模式的Hack代码将会更加严格地进行类型检查。其次,严格模式的Hack代码是根本无法调用PHP代码的,但是它可以调用耦合模式的Hack代码。
如果你正在编写一个全新的、100%纯正的Hack代码库,那么你不应该使用耦合模式。