2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PHPの関数型ヒントで勝手にキャストされる

Last updated at Posted at 2024-12-25

年末をゆるくお過ごしの皆様も、師走を身に染みて感じている皆様もこんにちは。
jof-fumiです。
この記事は、よりそうアドベントカレンダーの25日目の記事となります。

実はこの記事、さっき仕事中に見つけた事象をそのまま記事にしてみました。


PHPの関数のreturnの型ヒント(bool)を指定すると、暗黙変換される

以下のような関数があります。
この関数は、斎場の見学可否について、別システムから送られてくる値をコード値に変換するものです。

    private function getKengakuTypeId(?string $value): bool
    {
        return match ($value) {
            null => 1,
            '可' => 2,
            '不可' => 3,
            '条件付き' => 4,
            default => 1,
        };
    }

この関数に '可' を渡しているはずなのに、データベースを見ると1が登録されるという事象が発生しました。

原因の特定

この原因は、以下の通りです:

  1. match 関数は適切に 2 を返していた
  2. 型ヒント : bool によって、返り値が boolean 型にキャストされていた
    • その結果、getKengakuTypeId は true を返していた
  3. DB登録時に、さらに int 型にキャストされて 1 として登録された

つまり、match 関数の結果そのものには問題がなく、return の型ヒントによるキャストが原因でした。

テスト

以下のユニットテストを書いていたのですが、これが全てパスしてしまいました。

// tests/Unit/Test.php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use App\Models\Saijo;

class SaijoTest extends TestCase
{
    public function testGetKengakuTypeId()
    {
        $saijo = new Saijo();

        // '可' の場合
        $this->assertEquals(
            2,
            $saijo->getKengakuTypeId('可')
        );

        // '不可' の場合
        $this->assertEquals(
            3,
            $saijo->getKengakuTypeId('不可')
        );

        // '条件付き' の場合
        $this->assertEquals(
            4,
            $saijo->getKengakuTypeId('条件付き')
        );

        // null の場合
        $this->assertEquals(
            1,
            $saijo->getKengakuTypeId(null)
        );

        // その他の値の場合
        $this->assertEquals(
            1,
            $saijo->getKengakuTypeId('その他')
        );
    }
}

なぜパスしてしまうのか?

これは、assertEquals を使用しているためです。

例えば、true2 は型が異なりますが、assertEquals では等しいと判断されます。
型も含めて厳密に検査したい場合は、assertSame を使用する必要があります。

以下の通りですね。

% php -r "var_dump(3 == true);"
bool(true)
% php -r "var_dump(3 === true);"
bool(false)

結論

assertEqualsは使うな。

以上、皆様もお気をつけください。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?