【実務・中級編】PHPのisset()とempty()の罠を解体する:Hackの明示的Bool判定とNull合体演算子の適用 – Hack言語 コア・静的型システムとHHVMのアーキテクチャ解析バイブル

PHPの「曖昧さ」をHackの「厳格さ」で殺す:`empty()`と`isset()`の解体新書

Hackのコアを触っていると、PHP由来の「柔軟性という名の負債」に直面することがある。その筆頭が `empty()` と `isset()` だ。

これらは、開発者が「何となくの期待」を込めて書くコードの温床だ。`0` を渡したときに `false` になる `empty()` の挙動や、プロパティの有無と値を混同させる `isset()`。これらは型推論を根底から腐らせ、HHVMの最適化パスを阻害する。

今日は、型安全という武器を手に、PHPの曖昧な条件判定をHackの「明示的な記述」へ昇華させる技術を伝授する。

—

1. `empty()` の何が罪深いのか

PHPにおいて `empty($var)` は、「値が存在するか」ではなく「値がFalsyであるか」を判定する。この「存在」と「真偽値」の混同こそが、ランタイムエラーの温床だ。

悪い例(PHP的思考)

// 意図:IDが0(有効なID)なのに空と判定されてしまう
function processId(int $id): void {
if (empty($id)) { // 0 が渡されると、ここで真になる
throw new InvalidArgumentException(“ID is required.”);
}
// …
}

解体:Hackにおける正解

Hackでは「値があるか」と「値が有効か」を分離する。`null` は `null` として、`0` は `0` として明確に扱う。

use namespace HH\Lib\C;

function processId(?int $id): void {
// 1. Nullability を明示的に解決する
$id = $id ?? throw new InvalidArgumentException(“ID must be provided.”);

// 2. 値の妥当性は、型システムが保証する範囲で直接判定する
if ($id === 0) {
// 0 が有効なビジネスロジックである場合、ここを通る
}
}

—

2. `isset()` の欺瞞を `null` 合体演算子で剥ぎ取る

`isset()` は、配列のキー存在確認とプロパティのNULLチェックを同時に行う。だが、もし値が `null` だった場合、`isset()` は `false` を返す。これは「キーがない」のか「値がnullなのか」を曖昧にする。

リファクタリング:配列操作の鉄則

HHVMの型チェッカーを最大限に活かすなら、`C\contains_key` を使うべきだ。

use namespace HH\Lib\Dict;

// 悪い例:isset で判定し、その後でキャストを行うという無駄なステップ
function getValue(dict $data): int {
return isset($data[‘count’]) ? $data[‘count’] : 0;
}

// 良い例:HSLの力を使い、型安全を担保する
function getValue(dict $data): int {
// キーの存在を明示的に判定し、デフォルト値を安全に注入する
return $data[‘count’] ?? 0;
}

—

3. 実践:非同期API連携における「空」のハンドリング

APIから返却されるレスポンスのパース時に、`empty()` を使っているなら今すぐ捨てろ。HSLの `Vec` や `Dict` を組み合わせれば、型推論を止めずにクリーンな分岐が書ける。

プロダクションコード例

use namespace HH\Lib\Vec;

type ApiResponse = shape(‘items’ => vec);

function processResponse(ApiResponse $response): void {
$items = $response[‘items’];

// Vecが空かどうかは C\is_empty を使う
if (C\is_empty($items)) {
// 0件の場合の処理
return;
}

// 最初の要素にアクセスする場合も、インデックス存在チェックを型レベルで行う
$first = $items[0] ?? null;
if ($first is nonnull) {
// $first はここで string 型として推論される
echo $first;
}
}

—

アーキテクトからの提言:なぜこれが速いのか

HHVMは、型が固定されていればいるほど、JITコンパイラが「型ガード」の生成を省略できる。
`empty()` のような複雑な判定を行うと、HHVMはその都度、型を推測するためのランタイムチェックを挟まざるを得ない。

対照的に、`$val ?? $default` や `is nonnull` を使うコードは、型チェッカーがコンパイル時に「この値は決してNULLにならない」と証明できるため、HHVMは最適化された機械語へ直結させることができる。

結論:
1. `empty()` は禁止:代わりに `$x is null` や `$x === 0` を使え。
2. `isset()` は最小限に:キー存在判定には `C\contains_key` を選べ。
3. `??`(Null合体)を愛せ:デフォルト値の注入は、これが最も美しい。

型を厳格に定義することは、単にバグを減らすことではない。コードを、HHVMが最大限のパフォーマンスを発揮できる「理想的な状態」に導く行為なのだ。

今日からその汚れた `empty()` を消し去り、Hackの真の力を解き放て。それが、我々エンジニアが書くべき「美しいコード」の最低条件だ。

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