型システムを制するものはHackを制す
Hack and HHVM Advent Calendar 2018も中盤になってきましたので、
Hackの型システムに慣れるために、色々みていきます
紹介するものは全てstrict
前提です。
プリミティブ
公式ドキュメントにもありますが、まずは基本の型からです。
PHPとは微妙に異なります。
bool
boolは当然boolのみとなります。
<?hh // strict
namespace Acme\Hacklang;
class TypeSystem {
public function is(): bool {
return true;
}
public function is_is(bool $bool): bool {
return $bool;
}
}
int / float
intとfloatを混ぜて使うことはできません。
下記は共にTypeErrorです。
public function is(): int {
return 1.0;
}
public function is_is(float $bool = 0.1): int {
return $bool;
}
string
文字列も当然それ以外は利用できません。
array
これまでも紹介してきた様にarrayはPHPと同様にarrayだけでは不十分となります。
文字列のarrayを宣言しておいてintとなるとErrorとなります。
下記のは全てTypeErrorです。
public function failedStringVarray(): varray<string> {
return [1];
}
public function failedStringStringDarray(): darray<string, string> {
return ['hello' => 1];
}
public function failedStringArray(): array<string> {
return [1];
}
public function failedStringStringArray(): array<string, string> {
return ['hello' => 1];
}
public function failedNestedMixedArray(): array<mixed> {
return [
1,
'testing',
'hello' => 1234,
'nested' => [
1 => 2,
'testing',
'hello' => 1234,
]
];
}
public function failedMixedArray(): array<mixed, mixed> {
return [
1,
'testing',
'hello' => 1234,
'nested' => [
1 => 2,
'testing',
'hello' => 1234,
]
];
}
resource
PHPと同じです。
public function is(): resource {
return \fopen("ftp://user:password@example.com/somefile.txt", "w");;
}
他
プリミティブ型以外で利用するものです。
void
戻りがないことの宣言です。
ユニットテストの場合は基本的にvoidになるので、記述しなければいけません。
混合系
普通のものから特殊なものまで様々です。
mixed
Hackで開発する上で一番厄介で、なるべく利用して欲しくないのがこのmixedです。
いろんな型に加え、nullとvoidが許容されます。
mixedが記述されると、様々な手法でTypecheckerに理解可能なコードに書き直す必要があります。
下記のコードを例にしましょう。
public function mixedParameter(mixed $param): string {
return $param;
}
引数にmixedを使い、そのまま返却している例です。
これはこのままだとTypeErrorになるため処理が実行できません。
$paramが文字列かどうかを保証するコードに変更しなければいけません。
下記のコードは問題がないコードです。
public function mixedParameter(mixed $param): string {
if($param is string) {
return $param;
}
return '';
}
invariantを利用することもできます。
mixedは使えば使うほど分岐処理などが増えていきますので、
注意が必要です。
public function mixedParameter(mixed $param): string {
invariant($param is string, 'Type Error.');
return $param;
}
nonnull
nullではないことを表すものです。
?nonnull
にすると、mixedと同じ意味になります
public function nullableNonnull(): nonnull {
return 1234;
}
num
intとfloatが利用できる型です。
以下のは問題なく動作します。
public function returnNum(): num {
if (true) {
return 1.0;
}
return 1234;
}
arraykey
intとstringが利用できる型です。
public function returnKey(): arraykey {
if (true) {
return 'hello';
}
return 1234;
}
callable
PHPのものと意味は同じですが、記述方法が異なります。
HackではcallableだけではTypecheckerでOKになりません。
callableなものでも無名関数の引数・型、無名関数の戻りの宣言しなければなりません。
またPHPの場合は __invokeを実装したクラスも許容されていますが、
Hackの場合は __invokeが実装されていてもcallableにはなりません。
public function returnCallable(): (function(int): int) {
return function(int $int) {
return 1;
};
}
Tuple
多値をあらわすものです。
難しい型ではありません。
public function returnTuple(): (int, string) {
return tuple(1, 'testing');
}
Classname
ライブラリ開発などで多用するであろう型です。
className::classを返却したり引数に利用できるところで利用できます。
下記のはものはstdClassの例です。
public function returnClassname(): classname<\stdClass> {
return \stdClass::class;
}
Genericsを利用することで、様々なクラス名を扱うこともできます。
public function returnGenericsClass<T as classname<T>>(T $name): T {
return $name;
}
今回は型の紹介のみでした。