PHP 8 の新機能をLaravelで使ってみた

こんにちは❗フリーランス・エンジニアの 九保すこひ です。

さてさて、皆さんもよくご存知のとおりですが、LaraveだけでなくPHP自体もアップデートを繰り返していて、常に新しい機能が加わったりしています。

そして、来たる「2020.11.26」に次期バージョンのPHP 8がリリースされることになってます(私がPHPを使い始めたのがバージョン4でしたので、何か説明のできない興奮があります😂)

PHP 8の目玉機能としては、やはり「JITコンパイラ」による超高速化ですが、プログラミング的にもいくつか「おっ!」と思うものがありました。

そこで❗

今回は、その気になるPHP 8の新機能をLaravelで使ってみることにしました。

ぜひ皆さんのお役に立てましたら嬉しいです😊✨

「プレステも、もう5になるんですね」

開発環境: Laravel 8.x

関数に渡すパラメータの順番が自由になる

これまでのPHPでは、関数に渡す引数(パラメータ)は必ず順番を守る必要がありました。

例えば、Laravelのヘルパー関数Str::padLeft()を見てみましょう。
まずは、定義はこうなっています。

// Laravel から引用

public static function padLeft($value, $length, $pad = ' ')
{
    return str_pad($value, $length, $pad, STR_PAD_LEFT);
}

この引数の順番に注目してみると、もし関数を使いたい場合は、

  1. $value
  2. $lenth
  3. $pad

の順番でセットしないといけません。
例えば、こんなカンジです。

$value = '123';
$length = 10;
$pad = '0';

// 👇 引数の順番は決まってます
$text = Str::padLeft($value, $length, $pad);

しかし、PHP 8からは次のように書くことができます。

$text = Str::padLeft(
    value: '123',
    length: 10,
    pad: '0'
);

そのため、順番は関係なくなり、以下のように書いても同じ結果になります。

$text = Str::padLeft(
    pad: '0', // 👈 順番は気にしなくてOK
    length: 10, // 👈 ここも
    value: '123' // 👈 ここも
);

まだ実際の開発で使っていないですが、可読性は上がると思いますし、IDEが自動的にこの形式で自動入力してくれるなら、こっちの書き方もアリかなと思ってます👍(ただし、引数が少ない場合はなしの方がいいですね)

switch()が進化したようなmatch()関数

PHP 8には新しい条件分岐match()が追加されます。

これをLaravelのモデルで使ってみます。
以下は、商品の値段で分岐をする例です。

$item = Item::find(1);

$text = match($item->price) {
    500 => 'ワンコインです',
    1000, 2000, 3000 => '切りのいい値段です',
    default => '好評発売中'
};

$textの中身としては以下のとおりになります。

  • 値段が 500 の場合: 「ワンコインです」
  • 値段が 1000, 2000, 3000 の場合: 「切りのいい値段です」
  • それ以外: 「好評発売中」

チェーンメソッドでNullなら途中で終了する機能

チェーンメソッドというのは、以下のように->でつないだコードのことです。

$users = User::get();
$user_names = $users->filter(function($user) {

    return $user->id > 3;

})
->pluck('name')
->map(function($user_name) {

    return $user_name .'様';

});

この書き方はコードがすっきりするのでとても便利ですが、一点「うーん」な点がありました。

それが、「途中でnullが返ってきても実行が止まらず、結果エラーが出る」ということです。

これが、PHP 8では、?->を使うことで処理が途中で止まる(それ以降のコードはちゃんと実行されます)ようになりました。

例を見てみましょう。

public function index(Request $request)
{
    $user_name = $request->user()?->name;
}

この場合、user()NULLの場合、それ以降は無視されることになります。

もしこれまでの->だけの以下の場合、ログインしている場合は問題なく動きますが、そうでない場合は、Attempt to read property "name" on nullというエラーが発生します。

// ⚠ ここは、ログインしてないとエラーになります
$user_name = $request->user()->name;

そのため、これまでは三項演算子を使うかif文で分岐する必要がありました。

$user = $request->user();
$user_name = !is_null($user) ? $user->name : null;

※ ちなみに、PHP 7以降なら「Null Coalescing Operator」でもOKです。

$user_name = $request->user()->name ?? null;

ちょっと可読性的に大丈夫かな?と思う気もするんですが、コードが長くなるならとても便利な気がしています。

クラスのメンバ変数を省略して書ける

PHP 8ではクラス内で使うメンバ変数の定義を省略して書くことができるようになります。

ということで、LaravelMailableを使って見てみましょう❗

例えば、これまでのPHPでメンバ変数を使う場合、よく以下のようにコンストラクタの中でデータをセットしていました。

class Contacted extends Mailable
{
    // 省略

    private User $user; // 👈 メンバ変数を定義

    public function __construct(User $user)
    {
        $this->user = $user; // 👈 メンバ変数へデータを格納
    }

しかし、これからはコンストラクタだけで完結できるようになります。

class Contacted extends Mailable
{
    // 省略

    // 👈 メンバ変数の定義が不要

    public function __construct(private User $user) // 👈 private や public をつけるだけ
    {
        // 👈 メンバ変数への格納も不要!
    }

つまり、以下のようにとてもスッキリした形でコードを書くことができるようになります。

class Contacted extends Mailable
{
    // 省略

    public function __construct(private User $user)
    {
    }

これまで正直なところ、ココはめんどうだと感じていた部分なので、個人的にすごく嬉しい機能です👍

try ~ catch の変数を省略できるようになった

これまで try ~ catchを使う場合は以下のように、catch()の中には変数を指定する必要がありました。

try {

    echo $undefined; // わざとエラーを発生させる

} catch (\Exception $exception) {

    // エラーの場合

}

これが、PHP 8からは変数名の指定は不要になりました。

try {

    echo $undefined;

} catch (\Exception) { // 👈 変数が不要になりました

    // エラーの場合

}

そのため、エラー(例外)の中身を知る必要はないときには重宝するんじゃないでしょうか。

型を複数指定できる機能

PHP 7.4から以下のような「型付きプロパティ」が使えるようになりました。

class Item
{
    public int $id;
    public string $name;

// 省略

そして、PHP 8からは、複数の型を宣言できるようになります。

LaravelMailableで例を見てみましょう。

<?php

namespace App\Mail;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class Contacted extends Mailable
{
    use Queueable, SerializesModels;

    private string|User $user; // 👈 型を2つ指定してます

    public function __construct(string|User $user) // 👈 型を2つ指定してます
    {
        $this->user = $user;
    }

    public function build()
    {
        $user_name = $this->user->name ?? $this->user;

        return $this->to('admin@example.com')
            ->view('emails.contacted')
            ->with([
                'user_name' => $user_name
            ]);
    }
}

この中では、変数$userは「Userモデルか、文字列ならOK」ということになっています。

ただ、その昔Javaを書くときは型宣言は当たり前でしたが、PHPPythonがメイン言語になってからはあまり使わなくなってしまい、正直型の宣言はめんどうだな、なんて思うんですが皆さんはいかがでしょうか❓❓

インスタンスでも「::class」がつかえるようになった

これまで、インスタンスからクラス名を取得するにはget_class()を実行する必要がありました。

$user = User::find(1);
dd(get_class($user));

しかし、PHP 8からはシンプルに::classを使えるようになりました。

$user = User::find(1);
dump($user::class);

地味な変更ですが、可読性も上がっていいと思います👍

参考記事

今回、PHP 8の新機能で参考にさせていただいたページは以下の2つです。
この記事には書いていない記事もありますので、興味のある方はぜひご覧になってください。

What’s new in PHP 8:
https://stitcher.io/blog/new-in-php-8

【PHP8.0】PHP8.0の新機能
https://qiita.com/rana_kualu/items/fe7998fbe773544d5d25

ホントに、こういうきっちりとした記事を書いてくれる方には感謝しかありません。ありがとうございます!

正直、私も彼らのようになりたかったですが、あきらかに向いてないので、今後も「ゆるーく楽しい」記事でやっていきたいと思います👍

おわりに

ということで、今回はPHP 8の新機能をLaravelの中で使ってみました。

ちなみに今回紹介した中で個人的に好きなランキングをつけるとすると、次のとおりです。

  1. クラスのメンバ変数を省略して書ける
  2. try ~ catch の変数を省略できるようになった
  3. チェーンメソッドでNullなら途中で終了する機能

どうやら私は「できるだけなんでも省略したい」と考えているようです(笑)

まぁ、プログラマは「楽しようとする人」は適正があると言われているので、「ヨシ!」とすることにします。

ではでは〜❗

「現場猫ちゃん、かわいいですね😁」

開発のご依頼お待ちしております 😊✨ お問い合わせ
また、こちらもお待ちしております。
  • 実案件の開発サポート: 詳細
  • ツイッターのフォロー: 詳細
  • 投げ銭のご支援: 詳細
どうぞよろしくお願いいたします!
このエントリーをはてなブックマークに追加       follow us in feedly