declare(strict_types=1)の効果、暗黙の型変換を止める一行

declare(strict_types=1) とは、引数や戻り値の暗黙の型変換を止め、宣言どおりの型でなければ TypeError を投げさせる一行です。型の食い違いを早い段階で気づけるようになります。

普段は黙って型を変換してくれる

PHPは既定では親切で、型が合わなくても可能なら勝手に変換して受け入れてくれます。int を要求する引数に文字列の “3” を渡しても、3 に直して通してしまうんですね。便利な反面、意図しない変換がバグを覆い隠すことがあります。数値と思っていた値が実は文字列だった、みたいな取り違えが素通りしてしまうわけです。

function double(int $n): int
{
    return $n * 2;
}

double('5'); // 既定では通る('5' → 5 に暗黙変換)
double('abc'); // これはさすがにエラー

strict_typesで変換をやめさせる

ファイル先頭に declare(strict_types=1); を置くと、この暗黙変換が止まります。型が宣言どおりでなければ、その場で TypeError が飛ぶようになります。曖昧さが消えて、型の食い違いを早い段階で気づけるのが利点ですね。私は新規ファイルには機械的に付けるようにしています。

<?php

declare(strict_types=1);

function double(int $n): int
{
    return $n * 2;
}

double('5'); // TypeError: 文字列は受け付けない
double(5);   // OK

先頭必須、そして呼び出し側で効く

注意点が二つあります。まず declare は名前空間宣言より前、ファイルの本当に先頭でないと構文エラーになります。空行や別の文が挟まってもだめですね。もう一つは、厳格モードが効くのは「その関数を呼び出す側のファイル」の設定だという点です。関数の定義側ではなく、呼び出す側に declare があるかで挙動が決まります。

<?php
// この位置以外はNG。空行や echo が先にあると構文エラー
declare(strict_types=1);

// 効くかどうかは「呼ぶ側」の declare 次第、という点に注意

まとめ

strict_types はたった一行ですが、暗黙変換に頼らないコードへ切り替えるスイッチだと思います。型の食い違いを早期に落としてくれるので、私はデメリットより恩恵のほうが大きいと感じています。ファイルの本当の先頭に置くこと、効くのは呼び出し側であること、この二点だけ押さえておけば導入で迷うことはない気がします。

よくある質問

Q. declare(strict_types=1) はどこに書きますか?
A. 名前空間宣言より前、ファイルの本当の先頭に置きます。空行や echo が先にあると構文エラーになるので、開始タグの直後に書くのが基本です。

Q. 定義側と呼び出し側、どちらの declare が効きますか?
A. 効くのは関数を呼び出す側のファイルの設定です。定義側ではなく、呼ぶ側に declare があるかどうかで厳格モードになるかが決まります。

類似投稿

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です