【PHP】PHP8.0で実装されそうな便利な記法

  • 2020年6月23日
  • PHP

 PHP8.0は2020年11月26日にリリース予定のPHPの新バージョンです。この記事ではPHP8.0で導入されるであろう機能を紹介します。

Nullsafe operator

PHP: rfc:nullsafe_operator

[RFC] Nullsafe operator - Externals

 Nullsafe operator は null を参照しても問題なく動作を続行するための演算子です。具体的に何をするかというと次です。

// @see https://wiki.php.net/rfc/nullsafe_operator
/**
 *  Nullsafe operator なしの素朴な記述
 */
$country =  null;
// 参照途中の各要素(主にプロパティ)が null でないか都度検査する
if ($session !== null) {
    $user = $session->user;

    if ($user !== null) {
        $address = $user->getAddress();

        if ($address !== null) {
           // 全て not null ならば代入
            $country = $address->country;
        }
    }
}
// 最奥の if 文内までは入れていないならば $country === null

/**
 * Nullsafe operator あり
 */
// 途中で null を参照するとその時点で処理を打ち切って $country に null を代入
$country = $session?->user?->getAddress()?->country;

 これはJavaScriptの Optional chaining とほぼ同じ( JavaScript 側は値 undefined の処理が絡む)で、Laravelユーザ的にはヘルパ関数の optional がわかりやすいでしょう。

ヘルパ 6.x Laravel#optional

 Nullsafe operator を使うことで長大な null 検査を記述する必要がなくなります。

名前付き引数

PHP: rfc:named_params

[RFC] Named arguments - Externals

【PHP】名前付き引数が使える様になるかも – 株式会社シーポイントラボ | 浜松のシステム・RTK-GNSS開発

 以前記事に起こしたのでざっくり紹介します。

// @see https://wiki.php.net/rfc/named_params
// 名前付き引数なし
array_fill(0, 100, 50);

// 名前付き引数あり
array_fill(start_index: 0, num: 100, value: 50);
array_fill(value: 50, start_index: 0, num: 100);

 引数を名前で指定することができます。引数の数が多くても順番に気を配る必要がなくなります。

throw式

PHP: rfc:throw_expression

[RFC] throw expression - Externals

 throw が式として書けます。具体的には次です。

// throw式なし
if(! isset($nullableValue)){
    throw new InvalidArgumentException();
}
$value = $nullableValue;

// throw式あり
$value = $nullableValue ?? throw new InvalidArgumentException();

 文でなく式になることで今まで記述できなかった部分でも throw を書けるようになります。値の検査に合格したら代入、失敗したら例外、という処理は頻出します。その度に冗長に見える if 文を書くことに微妙に不満のあった自分としては割とうれしい変更です。

match式(厳格なswitch文)

PHP: rfc:match_expression_v2

[RFC][DISCUSSION] Match expression v2 - Externals

 match式はswitch文的な動作をする新たな式です。具体的に何をするかというと次です。

// @see https://wiki.php.net/rfc/match_expression_v2
// switch文による記述
switch ($this->lexer->lookahead['type']) {
    case Lexer::T_SELECT:
        $statement = $this->SelectStatement();
        break;

    case Lexer::T_UPDATE:
        $statement = $this->UpdateStatement();
        break;

    case Lexer::T_DELETE:
        $statement = $this->DeleteStatement();
        break;

    default:
        $this->syntaxError('SELECT, UPDATE or DELETE');
        break;
}

// match 式による記述
$statement = match ($this->lexer->lookahead['type']) {
    Lexer::T_SELECT => $this->SelectStatement(),
    Lexer::T_UPDATE => $this->UpdateStatement(),
    Lexer::T_DELETE => $this->DeleteStatement(),
    default => $this->syntaxError('SELECT, UPDATE or DELETE'),
};

 ぱっと見は短縮構文です。1ケースに1式しか用いられない代わりに 1/3 程に圧縮されました。これだけでも各caseの中に長々と処理を書いて switch 文を含む関数が恐ろしい長さになるという失敗を防げるうえ記述が楽になります。match 式が switch 文と異なる最大の点は条件式の比較が厳密な比較であることです。具体的には次です。

// @see https://wiki.php.net/rfc/match_expression_v2
/**
 * switch 文による期待しない動作の例
 */
switch ('foo') {
    // switch 文での比較は緩やかな比較で暗黙の型変換が起きます。
    // 'foo' を int 型に変換すると数字に換算できない文字列なので 0 になります。
    case 0:
      // 0 == 'foo' なのでこのケースに引っかかります
      $result = "Oh no!\n";
      break;
    case 'foo':
      $result = "This is what I expected\n";
      break;
}
echo $result; // Oh no!

/**
 * match 式による期待通りの動作の例
 */
echo match ('foo') {
    0 => "Oh no!\n",
    'foo' => "This is what I expected\n",
}; // This is what I expected
// match 式では厳密な比較をします。
// 'foo' === 0 は false と評価され"Oh no!\n"は echo されません
// 'foo' === 'foo' は true と評価されるので"This is what I expected\n"が echo されます。

 ありがたいですね。これのおかげで今まで switch 文を避けて大量の if, if else にしていた記述をより適した記述にできます。

view raw php8.md hosted with ❤ by GitHub

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

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

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

CTR IMG