【PHP】maxは引数の順番に応じて異なる値を返すことがある

  • 2024年5月28日
  • 2024年5月28日
  • PHP

 maxは引数の値の中で最大の値を返す関数です。これは例えば次のように使えます。

<?php

// 3つの乱数の中で最大のものを返す
var_dump(max(
    rand(1, 100),
    rand(1, 100),
    rand(1, 100),
));
// int(78)

 maxが引数に取れる値の型は自由です。次のような比較もエラーになりません。

<?php

var_dump(max(
    2,
    'a',
    [],
    new stdClass(),
    true,
    null,
));
// object(stdClass)#1 (0) {
// }

 これは極端なケースですが、次のようなケースは手なりにコードを書いていると比較的起きえます。

<?php

var_dump([
    "max(0, '0')"    => max(0, '0'),
    "max('0', 0)"    => max('0', 0),
    "max(null, 0)"   => max(null, 0),
    "max(0, null)"   => max(0, null),
    "max(null, '0')" => max(null, '0'),
    "max('0', null)" => max('0', null),
]);

// array(6) {
//  ["max(0, '0')"] => int(0)
//  ["max('0', 0)"] => string(1) "0"
//  ["max(null, 0)"] => NULL
//  ["max(0, null)"] => int(0)
//  ["max(null, '0')"] => string(1) "0"
//  ["max('0', null)"] => string(1) "0"
//}

 同じ値のセットを引数としているのにも関わらず異なる結果が返ってきています。これは異なる型を受け取りながらもそのまま処理する仕様とPHPの暗黙の型変換の組み合わせによって起きています。このような状態が現れるうるコードは不具合につながりやすいです。実際PHPのドキュメントにも次のようにあります。
PHP: max – Manual

警告

異なる型の値を引数として渡す際には注意しましょう。
max() が予期せぬ結果を返す可能性があるからです。

 このような挙動が起きないようにするためには型を制御した関数を作り、その中でmaxを実行するのが効果的です。例えば次のコードのようにできます。

/**
 * 指定された型の引数の最大値を返す
 * @param  mixed[]  ...$args
 * @return mixed
 */
function type_safe_max(...$args): mixed
{
    if (count($args) === 0) {
        throw new InvalidArgumentException('引数が空です。最低1つの引数を指定してください。');
    }
    $type = gettype($args[0]);

    foreach($args as $arg) {
        if(gettype($arg) !== $type) {
            throw new InvalidArgumentException('引数の型が一致しません。' . $type . '型の引数を指定してください');
        }
    }

    return max($args);
}
// 使用例
var_dump(type_safe_max(0, 1)); // int(1)
var_dump(type_safe_max('0', '1'));// string(1) "1"
var_dump(type_safe_max(null,0));// PHP Fatal error:  Uncaught InvalidArgumentException: 引数の型が一致しません

 これは引数の中の型が一致している場合にのみ動作するmaxです。他には特定の型へのキャストを明示するなどして作ることもできます。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG