【入門編】HHVMの型チェッカーを拡張する:カスタム属性を用いた静的解析の自動化 – Hack言語 コア・静的型システムとHHVMのアーキテクチャ解析バイブル

こんにちは!HHVMの内部構造やHackの厳格な型システムの世界へようこそ。チーフアーキテクトの私です。

他の言語、例えばPHPやTypeScriptからHackの世界に飛び込んできた開発者の多くが、その圧倒的な速度と「一切の妥協を許さない厳格な静的型システム(Strict Mode)」の美しさに魅了されますよね。

でも、開発現場が進むにつれて、こんな風に思ったことはありませんか?
「標準の型チェッカーだけでは表現しきれない、ウチのプロジェクト固有のビジネスルールやセキュリティ制約を、ビルド時に自動で検知させたい!」 と。

今回は、Hackが持つ強力な機能である「カスタム属性(Attribute)」をフックし、HHVMの型チェッカーの世界を拡張して独自の静的解析を自動化する極意を、優しく、そして深く解説していきますね。ここをクリアすれば、あなたも立派なHackアーキテクトの仲間入りです!

—

1. Hackの型チェッカーと「カスタム属性」の基本

Hackの静的型チェッカー(`hh_client` / `hh_server`)は、コードを実行する前に型エラーをミリ秒単位で検出してくれます。このチェッカーは非常に賢いのですが、標準機能だけでは「このメソッドの引数は、特定のフォーマットをクリアした文字列でなければならない」といった、ドメイン特有の制約まではデフォルトではチェックできません。

そこで登場するのがカスタム属性(Attribute)です。
属性を使うことで、クラスやメソッド、プロパティに「メタデータ」を付与できます。

イメージ図:静的解析のパイプライン

[ あなたのHackコード ]
↓ (カスタム属性が付与されている)
[ hh_client (型チェッカー) ]
↓
[ カスタム静的解析スクリプト (ASTを走査) ]
↓
[ 違反があればビルドを即座にブロック! ]

このように、コードに「印(属性)」をつけておき、それを解析ツールに読み込ませることで、独自のルールを強制させることができるのです。

—

2. 実践:カスタム属性の定義とコードへの適用

まずは、コード側でどのように属性を定義し、利用するのか見ていきましょう。Hackでは、属性は `<<__Rx>>` のようなシステム組み込みのものだけでなく、ユーザーが独自に定義することも可能です。

今回は例として、「センシティブなデータを扱うメソッドには、必ず監査ログの記録先を指定しなければならない」という独自ルールを強制するシステムを作ってみましょう。

実際に書くHackコード

// strict
namespace HackArchitect\Security;

/

  • 監査ログの記録先を強制するカスタム属性
  • [[__Attribute]] を付与することで、属性として機能させます。

/
<<__Attribute(UserAttribute::TARGET_METHOD)>>
class AuditRequired implements \HH\ClassAttribute {
public function __construct(public string $logDestination) {}
}

class UserProfileService {

// 【OKな例】カスタム属性にログ先(”security_db”)が明示されている
<>
public function updatePassword(int $userId, string $newPassword): void {
// パスワード更新のロジック
}

// 【NGな例になりうるメソッド】
// センシティブな処理なのに属性がついていない、または不正な値が入っている場合
public function deleteUserAccount(int $userId): void {
// アカウント削除のロジック(本当は属性が必要!)
}
}

ここがポイント!

  • `<<__Attribute(UserAttribute::TARGET_METHOD)>>` により、この属性が「メソッドに対してのみ付与できる」という制約をコンパイラレベルでかけられます。文法ミスを未然に防ぐHackらしいアプローチですね。

—

3. 型チェッカーを拡張する静的解析ツールの設計

属性を貼るだけでは、ただの「飾り」になってしまいます。これを「静的解析のルール」として強制するために、HackのAST(抽象構文木)を走査するカスタムチェッカーをスクリプトとして構築します。

Hackには、コードの構造をJSON形式などで出力する仕組みや、HHVMのライブラリを通じてASTを解析する手段が用意されています。ここでは概念的なアプローチとして、カスタムチェッカーがどのようにコードを検証するかを見てみましょう。

// strict
namespace HackArchitect\Analyzer;

use namespace HH\Lib\{C, Str, Vec};

/

  • 独自の静的解析ランナーのイメージ

/
class AuditAttributeAnalyzer {

public static function analyzeCodebase(vec $classNames): bool {
$hasError = false;

foreach ($classNames as $className) {
$reflector = new \ReflectionClass($className);

foreach ($reflector->getMethods() as $method) {
// メソッド名が ‘delete’ または ‘update’ で始まる重要処理か?
$isSensitive = Str\is_prefix($method->getName(), ‘delete’) ||
Str\is_prefix($method->getName(), ‘update’);

if ($isSensitive) {
// AuditRequired 属性がついているかチェック
$attributes = $method->getAttributes();
if (!C\contains_key($attributes, \HackArchitect\Security\AuditRequired::class)) {
\fprintf(
\STDERR,
“【静点解析エラー】メソッド %s::%s は機密処理ですが、<> 属性がありません。\n”,
$className,
$method->getName()
);
$hasError = true;
}
}
}
}

return $hasError;
}
}

この解析スクリプトをCI/CDパイプライン(GitHub Actionsなど)や、ローカルの `hh_client` のフックとして組み込むことで、「属性の付け忘れ」を人間ではなくマシンが100%確実に検知できるようになります。

—

4. 陥りやすい文法エラーと注意点

Hackでカスタム属性やメタプログラミング的なアプローチを取る際、初心者がハマりやすいポイントをいくつかお伝えしておきますね。

1. Strict Mode (`// strict`) のし忘れ

  • Hackの恩恵を最大限に受けるため、解析ツール側もコード側も必ず最上位の厳格モードで記述してください。動的な型混じりのコード片があると、リフレクションやASTの構造が不安定になります。

2. 属性ターゲットの指定ミス

  • `<<__Attribute(UserAttribute::TARGET_CLASS)>>` と定義したのに、メソッドに付与してしまった場合、型チェッカーが即座にビルドエラーを吐きます。「あれ、なんで動かないんだろう?」と思ったらまずターゲットのスコープを確認しましょう。

3. 実行時コストの誤解

  • 属性やリフレクションは便利ですが、あまりに過剰に実行時(Runtime)の処理に組み込むとHHVMの最適化を阻害する場合があります。「静的解析(ビルド時・CI時)で検証し、実行時は極力クリーンに保つ」のがHackアーキテクトの黄金律です。

—

まとめ

いかがでしたか?今回は「カスタム属性を用いた静的解析の自動化」という、一歩進んだHackの活用術を解説しました。

  • カスタム属性でコードに意味のあるメタデータを付与する。
  • 型チェッカーや静的解析スクリプトと組み合わせることで、チーム全体のコーディング規約やセキュリティ要件を自動で強制する。

ここをマスターすれば、大規模なコードベースであっても、品質の揺らぎを完全にコントロールできるようになります。
あなたのHackライフが、よりスピーディで、より堅牢なものになることを応援しています。それでは、次のアーキテクチャでお会いしましょう!

タイトルとURLをコピーしました