PHP7からは引数のデフォルト値は、次のように作り込むことで、null
が渡されたらデフォルト値を使う関数を実装することができる。
- 引数の型宣言はnullableにする
- 関数シグネチャの引数デフォルト値は
null
にする - 本当のデフォルト値はNULL合体演算子
??
で表現する
たとえば次のように:
// 四角形の大きさを返す関数
function rect(?int $width = null, ?int $height = null): array
{
return [$width ?? 10, $height ?? 10];
}
// 2つの引数どちらもデフォルト値を使う
assert(rect() === [10, 10]);
assert(rect(null, null) === [10, 10]);
// 2つの引数どちらも与える
assert(rect(20, 30) === [20, 30]);
// 1つ目の引数はデフォルト値を使う
assert(rect(null, 30) === [10, 30]);
なぜ関数のシグネチャにデフォルト値がだめか
PHPでは慣習として引数にnull
渡すことは、デフォルト値を使うという意味になるが、型宣言をしているとFatalエラーが発生するため、関数のシグネチャにデフォルト値を持つことができない。
function rect(int $width = 10, int $height = 10): array
{
return [$width, $height];
}
// 2つの引数どちらもデフォルト値を使う
assert(rect() === [10, 10]);
assert(rect(null, null) === [10, 10]); // Fatal error: Uncaught TypeError: Argument 1 passed to rect() must be of the type integer, null given
// 2つの引数どちらも与える
assert(rect(20, 30) === [20, 30]);
// 1つ目の引数はデフォルト値を使う
assert(rect(null, 30) === [10, 30]); // Fatal error: Uncaught TypeError: Argument 1 passed to rect() must be of the type integer, null given
引数の型宣言をnullableにすることでFatalは発生しなくなるが、今度は関数シグネチャのデフォルト値が使われなくなる。
function rect(?int $width = 10, ?int $height = 10): array
{
return [$width, $height];
}
// 2つの引数どちらもデフォルト値を使う
assert(rect() === [10, 10]);
assert(rect(null, null) === [10, 10]); // Fail: actual = [null, null]
// 2つの引数どちらも与える
assert(rect(20, 30) === [20, 30]);
// 1つ目の引数はデフォルト値を使う
assert(rect(null, 30) === [10, 30]); // Fail: actual = [null, 30]
これはPHP7だからというわけではなく、PHP7以前からある仕様だ。PHP7でnull合体演算子が登場するまではif
や三項演算子で対処していた。それが今は書きやすくなっているというだけだ。
function rect($width = null, $height = null): array
{
return [$width ? $width : 10, $height ? $height : 10];
}
// 2つの引数どちらもデフォルト値を使う
assert(rect() === [10, 10]);
assert(rect(null, null) === [10, 10]);
// 2つの引数どちらも与える
assert(rect(20, 30) === [20, 30]);
// 1つ目の引数はデフォルト値を使う
assert(rect(null, 30) === [10, 30]);
所感
nullableな型宣言の引数だったら、nullを渡しときはデフォルト値を使ってくれればいいのに、かゆいところに手が届かない感がありますね。 #PHPhttps://t.co/UAd66lTeky
— ❄️suin (@suin) 2018年8月2日