Typechecker模式

2018-10-28 11:43 更新

在編寫Hack代碼時,通常會啟動文件<?hh并開始編寫代碼。但是,一個頂線實際上在Typechecker解釋代碼方面非常重要。

部分模式

Hack文件中的代碼<?hh以其頂部的四個字符開頭,據(jù)說處于部分模式。這意味著typechecker會檢查一下它可以,但不再有; 它不堅持全面覆蓋。部分模式很好用于開始逐漸輸入現(xiàn)有的代碼。以下是部分模式的規(guī)則:

  • 您可以與PHP文件完全互操作 - 您可以調(diào)用函數(shù)并使用Typechecker看不到的類。該代碼假設(shè)存在于某個<?php文件中。見的討論assume_php配置選項對于這意味著什么,為什么它可能是不希望,以及如何改變它的討論。
  • 您可以在頂層編寫代碼(即外部函數(shù)和方法),但不會進行類型檢查。為了最大化Typechecker在部分模式下檢查代碼的能力,通常的做法是將所有頂級代碼包裝到一個主要功能中,并將該功能的調(diào)用作為頂級的唯一代碼。
  • 您可以使用引用&,但是typechecker不會嘗試檢查它們(為了進行類型檢查,它忽略&)。嘗試不使用引用,因為您可以輕松地使用它們來打破類型系統(tǒng)。
  • 您可以無錯誤地訪問superglobals。
<?hh

namespace Hack\UserDocumentation\TypeChecker\Modes\Examples\Partial;

use \Hack\UserDocumentation\TypeChecker\Modes\Examples\NonHack as NonHack;

// This function isn't type annotated, so callers will be able to do whatever
// they want with its result. However, the typechecker does still look at and
// check the body of the function.
function foo() {
  $a = 1;
  // This will geneate a type error:
  //   an int does not allow array append (Typing[4006])
  $a[] = 2;
}

class A {
  private int $x;

  public function __construct() {
    $this->x = 9;
  }

  public function getX(int $y): ?int {
    return $y > 4 ? $this->x : null;
  }

  // You can even have non-type annotated code in the same class as
  // type annotated code.
  public function notTyped($z) {
    return "Hello" . $z;
  }
}

function bar(): int {
  $a = new A();

  // Not typechecked either. So we can pass an int and it will be converted to
  // a string by the runtime, luckily.
  echo $a->notTyped(3);

  // The return value from this call is not typechecked since B is in a PHP
  // file -- the typechecker assumes we know what we are doing since the
  // annotation is missing.
  $b = NonHack\B::getSomeInt();
  echo NonHack\php_func(3, $b);

  $i = $a->getX($b);
  if ($i !== null) {
    return $i;
  } else {
    return 0;
  }
}

bar();

Output

string(4) "1004"
Hello33100

請注意,我們已經(jīng)注釋了一些代碼,但不是全部。無論該功能本身的注釋如何,都會檢查推送的代碼

嚴(yán)格模式

hack文件為:

<?hh // strict

意味著Typechecker在該文件中強制執(zhí)行嚴(yán)格的輸入規(guī)則。如果在所有可能的情況下,使用嚴(yán)格模式啟動新項目 - 如果代碼庫中的每個文件都處于嚴(yán)格模式,則Typechecker的覆蓋范圍將最大化,因為它將能夠完全檢查所有內(nèi)容,并且在運行時不會出現(xiàn)類型錯誤。

以下是嚴(yán)格模式的規(guī)則:

  • 必須對所有函數(shù)和方法進行完全注釋,即必須完全指定它們的參數(shù)和返回類型。任何可以具有類型注釋的位置都必須有一個。
  • 所有被調(diào)用的函數(shù)和引用的類必須在Hack文件中定義。因此,例如,如果您的嚴(yán)格模式代碼嘗試使用<?php文件中定義的類,則會出現(xiàn)錯誤,因為Typechecker不會查找<?php文件,并且不會知道該類。但是,從嚴(yán)格模式,您可以調(diào)用部分和聲明模式下的Hack代碼。
  • 允許在頂層是唯一碼require,require_once,include,include_once,namespace,use,和類,函數(shù)的定義枚舉和常量。
  • 沒有任何參考&。
  • 沒有訪問superglobals。

嚴(yán)格模式的是你想要的模式。整個Typechecker的好處是可以使用的,應(yīng)該確保零運行時類型的錯誤。

<?hh // strict

namespace Hack\UserDocumentation\TypeChecker\Modes\Examples\Strict;

use \Hack\UserDocumentation\TypeChecker\Modes\Examples\NonHack as NonHack;

function foo(): void {
  $a = 1;
  // This will generate a type error:
  //   an int does not allow array append (Typing[4006])
  $a[] = 2;
}

class A {
  private int $x;

  public function __construct() {
    $this->x = 9;
  }

  public function getX(int $y): ?int {
    return $y > 4 ? $this->x : null;
  }

  // In partial, this didn't have to be annotated. In strict, it does.
  public function notTyped(string $z): string {
    return "Hello" . $z;
  }
}

function bar(): int {
  $a = new A();
  // This is typechecked, so we can't pass an string-y int; we must pass a
  // string
  echo $a->notTyped("3");

  // Cannot call these in strict mode:
  //    Unbound name:
  //       Hack\UserDocumentation\TypeChecker\Modes\Examples\NonHack\B
  //       (an object type) (Naming[2049])
  $b = NonHack\B::getSomeInt();
  //    Unbound name:
  //       Hack\UserDocumentation\TypeChecker\Modes\Examples\NonHack\php_func
  //       Typing[4107])
  echo NonHack\php_func(3, $b);

  $i = $a->getX(100);
  if ($i !== null) {
    return $i;
  } else {
    return 0;
  }
}

// This can't be in strict mode either. You need to put this in partial file
// and include it from this file. For the purposes of this example, though,
// we'll just suppress the error.

/* HH_FIXME[1002] So we can get interesting type-checking errors */
bar();

Output

string(4) "1004"
Hello33100

請注意,我們不能再調(diào)用該<?php文件,并且Hack文件中的所有實體都被注釋。

聲明模式

hack代碼為:

<?hh // decl

處于聲明模式。聲明模式代碼沒有類型檢查。然而,提取了在decl模式下的函數(shù),類等的簽名,并且在檢查其他代碼時被Typechecker使用。在轉(zhuǎn)換使用PHP編寫的代碼時,聲明模式是最有用的:雖然該代碼的正文可能具有您不想立即處理的類型錯誤,但仍然有益于使該代碼的簽名,至少其唯一存在,對其他代碼可見。事實上,Hack的一個非?;镜倪w移路徑是將所有<?php文件更改為decl模式,然后逐個開始采取每個文件并使其部分。

新的hack代碼應(yīng)該永遠寫在DECL模式。

<?hh // decl

// Before this was <?php code. Now the typechecker can see the signatures of
// these functions and classes for when Hack calls them, even in strict mode.

namespace Hack\UserDocumentation\TypeChecker\Modes\Examples\Decl;

function php_func($x, $y) {
  return $x . $y;
}

class B {
  static function getSomeInt() {
    return 100;
  }
}
<?hh // strict

namespace Hack\UserDocumentation\TypeChecker\Modes\Examples\CallIntoDecl;

require __DIR__ . '/decl.inc.php';
// This actually makes the call to calling_into_decl() since we cannot have
// top level functions in strict mode
use \Hack\UserDocumentation\TypeChecker\Modes\Examples\Decl as Decl;

function calling_into_decl(): string {
  // If php_func wasn't in decl mode, then we would get an unbound name error.
  // As it is, we can call this function and the typechecker will ensure we are
  // passing in the right number of arguments, but not the types of them.
  return Decl\php_func("a", "b");
}
<?hh

namespace Hack\UserDocumentation\TypeChecker\Modes\Examples\CallIntoDecl;

var_dump(calling_into_decl());

Output

string(2) "ab"

該示例顯示所有三種模式。首先,它顯示一個以前存在的聲明模式文件<?php。除了標(biāo)題更改之外,沒有添加任何其他內(nèi)容。然后它顯示一個嚴(yán)格的模式文件調(diào)用到declare文件。Typechecker知道函數(shù)和類的簽名,并且可以確?;镜臇|西,例如是否調(diào)用命名實體并傳遞正確數(shù)量的參數(shù)。最后,我們有一個部分模式文件實際上以嚴(yán)格模式調(diào)用該函數(shù),因為我們不能在嚴(yán)格模式下進行頂層函數(shù)調(diào)用。

混合模式

如上例所示,模式可以自由混合; 您的項目中的每個文件可以處于不同的Typechecker模式。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號