Laravel 10を見学する

Laravel 10を見学する

こんばんは。エンジニアの山下です。

Laravel 10が2023年2月14日にリリースされたので、その内容をリリースノートを追いながら確認します。

サポート

まずver10とその前後のサポート期間については以下の通りです。 (https://laravel.com/docs/10.x/releases#support-policy より引用)

Version PHP version Release バグ修正対応期間 セキュリティ修正対応期間
8 7.3-8.1 2020年9月8日 2022年7月26日 2023年1月24日
9 8.0-8.1 2022年2月8日 2023年8月8日 2024年2月6日
10 8.1-8.2 2023年2月14日 2024年8月6日 2025年2月4日

既にver8はメンテナンスの対象外ですね、時の流れ恐るべしです。

また、ver10の動作に必要なPHPのバージョンは8.1-8.2なので、今回のデモではphp8.2.4を使用します。

型・タイプヒントの強化

https://laravel.com/docs/10.x/releases#types

updates the application skeleton and all stubs utilized by the framework to introduce argument and return types to all method signatures. In addition, extraneous "doc block" type-hint information has been deleted.

「application skeleton」と「stubs」はおそらく、Laravelが自動で生成してくれるコード群のことをさしています。

「php artisan xxx」で生成されるようなコードにも、以前に増して型情報を定義してくれるようです。

リポジトリのdiffで修正内容を見ると確認できるのですが、確かに引数や返り値に対して型が指定されている箇所が多く見られ、application skelton and all stubs ...と記載されている通り、.stubファイルにも型に関する修正が確認できます。

PHP8.xへの対応

リリースノートには記載がないのですが、PHP8への対応は押さえておきます。コーディングする際のお手本として、特に新しい書き方へ移行する修正方法・書き方はキャッチアップしておきたいです。

catch()の変数を省略

この修正はかなり多く目にします。

PHP8.0からはcatchの変数を省略することができます。

// before
try {} catch(Throwable $e) {}
// after
try {} catch(Throwable) {}

protected → public readonly

readonlyはPHP8.1以降で使える宣言の仕方で、プロパティが初期化後に変更されないようにすることができます。

変更の経緯ですが、クラスの外からprotected $nameそのものを取得したいという要望が発端で、一時はgetterとしてpublic getGuardName()の実装も検討されますが、結果publicをprotectedに変更しreadonlyが付与されました。

class SessionGuard implements StatefulGuard, SupportsBasicAuth {

  // before
  protected $name
  // after
  public readonly $name
    
  public function __construct($name,
                            /*引数省略*/
                            )
  {
        $this->name = $name;
                //以下省略
    }
        
    /**
     * Get a unique identifier for the auth session value.
     *
     * @return string
     */
    public function getName()
    {
        return 'login_'.$this->name.'_'.sha1(static::class);
    }
        
    /**
     * Get the name of the cookie used to store the "recaller".
     *
     * @return string
     */
    public function getRecallerName()
    {
        return 'remember_'.$this->name.'_'.sha1(static::class);
    }
}

array_is_listの使用

PHP8.1以降で使える関数で、名前の通り配列がリストかどうかを確認します。

ここでいうリストとは、キーが数値の0から順番に並んでいる配列(連想配列)のことです。

print_r(['a', 'b', 'c']);
/*
Array
(
    [0] => a
    [1] => b
    [2] => c
)
*/

array_is_list(['a', 'b', 'c']);
// true

array_is_list(['0'=>'a','1'=> 'b','2'=> 'c']);
// true
// '0'は0に変換されます。

Laravelの話に戻りますが、array_is_listは\Illuminate\Collections\Arr::isAssoc()の代替として使われており、isAssoc自体もまだ存在しています。(実際にはarray_is_listの否定がisAssoc)

  public static function isAssoc(array $array)
  {
      // before
      $keys = array_keys($array);
      return array_keys($keys) !== $keys;

      // after
      return ! array_is_list($array);
  }

元々の実装も良いですね。

また、isAssocからarray_is_listへの変更も確認できます。 https://github.com/laravel/framework/compare/v9.52.4...v10.4.1#diff-770e6afc4f120d519e68c9f0b8de5fc5694eb0bc558b52f7464db8d9bf10e50fL458

attribute

PHP8.0以降で使えるアトリビュートも発見しました。

Illuminate\Cache\Console\PruneStaleTagsCommandにattributeがついています。

$command = new \Illuminate\Cache\Console\PruneStaleTagsCommand();
(new ReflectionClass($command))->getAttributes();

/*
[
  ReflectionAttribute {#3739
    name: "Symfony\Component\Console\Attribute\AsCommand",
    arguments: [
      "name" => "cache:prune-stale-tags",
    ],
  },
]
*/

プロパティの$nameと$descriptionを削除して、attributeを変更してみます。

#[AsCommand(name: 'cache:TEST', description: 'hello, i\'m in attribute')]
class PruneStaleTagsCommand extends Command
{}

bashから「php artisan list」でコマンドの一覧を確認すると、指定した内容が表示されています。 diffを読むのはこの辺にしておいて、リリースノートに戻ります。

Laravel Pennant

https://laravel.com/docs/10.x/releases#laravel-pennant

新しいファーストパーティのパッケージ「Laravel Pennant」(以下Pennant)が追加されたようです。

アプリケーションの機能を管理するようなことが出来るらしく、例えば...新しく実装した機能をとりあえず有料課金ユーザだけが使用できるようにして、だんだんとロールアウトするようなケースで有効のようです。

Process操作

https://laravel.com/docs/10.x/releases#process

Symfony Processを優しくラップして包み込み、テストのためのFake,Mock機能を提供しています。

Facadeとして公開されているので、Process::run('any-command') とするだけでコマンドが実行できます。

さらにProcess::forever()の返り値Illuminate\Process\PendingProcessにはTTYモードがあり、tinkerからvimを開くこともできるようです。

非同期(バックグラウンド)で処理をするにはProcess::start('any-command')とするだけです。

tinkerで試してスクショしました。start()を呼び出した直後に次のコマンドが入力可能になり、running()ではプロセスが終了したかどうかを確認しています。

artisan makeコマンドに対話モード追加

https://laravel.com/docs/10.x/releases#generator-cli-prompts

「あれmake:modelって引数何だっけ...」はあるあるかと思いますが、そんな時はartisan make:modelとだけ入力すればオプションの値をコマンドから質問されるようになりました。

百聞は一見にしかずですね。nodeのcreate-react-appを思い出します。

Test Profiling

https://laravel.com/docs/10.x/releases#test-profiling

artisan testへ--profile(引数なし)オプションが追加されました。

各テストに掛かる時間を表示してくれるようなので、軽くテストを書いて試してみます。せっかくなのでProcessを使ってSleepを呼びます。

// routes/api.php
Route::group(['namespace' => 'sleep'], function() {
    Route::get('/wait/:t', fn(int $t) => Process::run("sleep $t"));
    Route::get('/async/:t', fn(int $t) => Process::start("sleep $t"));
});

// tests/Feature/SleepTest.php
  public function test_wait_1(): void
  {
      $response = $this->get('/api/wait/1');
      $this->assertTrue(true);
  }

  public function test_wait_5(): void
  {
      $response = $this->get('/api/wait/5');
      $this->assertTrue(true);
  }

  public function test_async_1(): void
  {
      $response = $this->get('/api/async/1');
      $this->assertTrue(true);
  }

  public function test_async_5(): void
  {
      $response = $this->get('/api/async/5');
      $this->assertTrue(true);
  }

php artisan test --profileを実行すると、Top 10 slowest tests:と題して遅いテストランキングが表示されています。

その他

その他にもプロジェクト作成時にテストライブラリPestの導入をするためのコマンドオプションや開発環境のモニタリングツールTelescopeとキュー、ワーカに特化したモニタリングツールHorizonのUIが刷新され、よりモダンになったようです。

詳しくはリリースノートを確認してみてください。

Webサイト・システムの
お悩みがある方は
お気軽にご相談ください

お問い合わせ 03-6380-6022(平日09:30~18:30)

出張またはWeb会議にて、貴社Webサイトの改善すべき点や
ご相談事項に無料で回答いたします。

無料相談・サイト診断 を詳しく見る

多くのお客様が気になる情報をまとめました、
こちらもご覧ください。