44
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHP7からは引数デフォルト値にはNull合体演算子「??」を使うと良い

Last updated at Posted at 2018-08-02

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]);

所感

44
17
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
44
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?