Slide 1

Slide 1 text

© 2012-2024 BASE, Inc. 2024/03/08 PHPerKaigi2024 PHP8の機能を使って堅牢にコードを書く

Slide 2

Slide 2 text

© 2012-2024 BASE, Inc. 2 氏名:Futoshi Endo 所属:BASE株式会社 業務:バックエンド エンジニア 趣味:料理、音楽鑑賞、散歩 奥さんと、豆柴(どんちゃん)の三人で楽しく暮 らしています。 ● Endo Tech Blog ● https://scrapbox.io/fendo181/ Fendo181 自己紹介

Slide 3

Slide 3 text

© 2012-2024 BASE, Inc. 3 自己紹介 PHPカンファレンス関西2024にコアスタッフとして参加しました PsySHを使った効率的なデバッグ方法について

Slide 4

Slide 4 text

© 2012-2024 BASE, Inc. 4 サービス紹介

Slide 5

Slide 5 text

© 2012-2023 BASE, Inc. アジェンダ 5

Slide 6

Slide 6 text

© 2012-2024 BASE, Inc. アジェンダ 6 ● 今日の発表ゴール ● PHP8の機能の紹介 ● PHP8の機能を使ってコードを書いてみる ● まとめ

Slide 7

Slide 7 text

© 2012-2023 BASE, Inc. 今日の発表ゴール 7

Slide 8

Slide 8 text

© 2012-2024 BASE, Inc. 今日の発表ゴール 8 1 2 PHP8で追加された主な機能について理解できる PHP8で追加された機能を使って堅牢な コードを書けるようになる。

Slide 9

Slide 9 text

© 2012-2024 BASE, Inc. 今日の発表ゴール 9 1 2 PHP8で追加された主な機能について理解できる PHP8で追加された機能を使って堅牢な コードを書けるようになる。

Slide 10

Slide 10 text

© 2012-2024 BASE, Inc. 10 堅牢とは...? 今日の発表ゴール

Slide 11

Slide 11 text

© 2012-2024 BASE, Inc. 11 今日の発表ゴール 関連するキーワードとしては...

Slide 12

Slide 12 text

© 2012-2024 BASE, Inc. 12 今日の発表ゴール 関連するキーワードとしては... エラー処理が適切である セキュリティが確保されている 効率的である メンテナンスが容易である 予期しない入力や状況に対応してる テストが充実している

Slide 13

Slide 13 text

© 2012-2024 BASE, Inc. 13 それって具体的にどんなコードを書くのか..? 今日の発表ゴール

Slide 14

Slide 14 text

© 2012-2024 BASE, Inc. 14 PHP8の機能を紹介しながら 「堅牢なコード」 を書いてみる 今日の発表ゴール

Slide 15

Slide 15 text

© 2012-2023 BASE, Inc. 15 PHP8で追加された 主な機能について紹介

Slide 16

Slide 16 text

© 2012-2024 BASE, Inc. 16 PHP8.0 (2020/11/26) ● 名前付き引数 ● Attribute ● Constructor Property Promotion ● Match 式 ● Union 型 ● Nullsafe 演算子 など

Slide 17

Slide 17 text

© 2012-2024 BASE, Inc. 17 Constructor Property Promotionは、クラスのプロパティ宣言とコンストラ クタでの初期化を一つのステップで行えるようにする機能です。これにより、 コードの冗長性を減らし、より簡潔で読みやすいコードを書くことが可能になり ます。 name = $name; $this->age = $age; }

Slide 18

Slide 18 text

© 2012-2024 BASE, Inc. 18 'OK', 400 => 'Bad Request', 500 => 'Internal Server Error', default => 'Unknown', }; echo $status; match式を使用すると、switch文より簡潔に記述する事ができます。match式 は自動的にbreakを含んでいるため、複数のケースが誤って実行される心配はあ りません。また、match式 は、型と値についても厳密な比較を行います

Slide 19

Slide 19 text

© 2012-2024 BASE, Inc. 19 https://www.php.net/releases/8.0/ja.php

Slide 20

Slide 20 text

© 2012-2024 BASE, Inc. 20 PHP8.0 (2020/11/26) ● 名前付き引数 ● Attribute ● Constructor Property Promotion ● Match 式 ● Union 型 ● Nullsafe 演算子 など PHP8.1 (2021/11/25) ● Enum型 ● 読み取り専用プロパティ (Readonly Properties) ● 交差型 ● Never型 など

Slide 21

Slide 21 text

© 2012-2024 BASE, Inc. 21 Enum型を使用することで、期待される特定の値のみを受け入れるように制約を かけることができ、これによりコードの意図が明確になり、エラーの可能性を減 らすことができます。

Slide 22

Slide 22 text

© 2012-2024 BASE, Inc. 22 読み取り専用プロパティ(Readonly Properties)は、プロパティが初期化さ れた後に変更することができないことを保証します。この機能は、不変の状態を 持つオブジェクトを作成する際に特に有効です。 name; // Endu echo $user->age; // 30 // readonly プロパティは変更できないため、以下のコードはエラーになる $user->name = "Bob"; // エラー: Cannot modify readonly property User::$name

Slide 23

Slide 23 text

© 2012-2024 BASE, Inc. 23 PHP8.0 (2020/11/26) ● 名前付き引数 ● Attribute ● Constructor Property Promotion ● Match 式 ● Union 型 ● Nullsafe 演算子 など PHP8.1 (2021/11/25) ● Enum型 ● 読み取り専用プロパティ (Readonly Properties) ● 交差型 ● Never型 など PHP8.2(2022/12/08 ) ● 読み取り専用クラス (Readonly Classes) ● Random 拡張モジュール ● Never型 など ● null, false, true が独立し た型として使える ● 動的なプロパティが非推奨 に など

Slide 24

Slide 24 text

© 2012-2024 BASE, Inc. 24 name; // Endu // しかし、プロパティは読み取り専用なので、変更しようとするとエラーになります $profile->name = "Bob"; // エラー: Cannot modify readonly property UserProfile::$name 読み取り専用クラス(Readonly Classes)はクラスのすべてのプロパティが読 み取り専用であることを意味します。この機能を使用すると、クラスのインスタ ンスが一度作成されると、その状態が変更されないことが保証されます。読み取 り専用クラスは、データオブジェクトが不変であるべき場合に特に便利です。

Slide 25

Slide 25 text

© 2012-2024 BASE, Inc. 25 PHP8.3 (2023/11/23) ● クラス定数の型付け ● クラス定数の文字列指定 ● #[\Override]の追加 ● json_validate()の追加 ● 読み取り専用プロパティの ディープクローン など... PHP8.4 (???)

Slide 26

Slide 26 text

© 2012-2024 BASE, Inc. ここまでのまとめ 26 ● PHP8.0 ~ PHP8.3までで追加された機能をざっくり紹介しました! ● 一部の機能しかとりあげれてないが、他にも沢山の改善がある ○ PHP JIT ○ throw式の導入 ● PHPStanと組み合わせて使うとより、より安全にコードが書けるようになる。 ● ちなみにPHP 8.0のセキュリティサポートは既に 2023/11/26 で終了している...! ○ PHP8.1のセキュリティサポートは 2024/11/25で終了 ■ なるべく新しいPHP8.xを使っていきましょう...!!

Slide 27

Slide 27 text

© 2012-2023 BASE, Inc. 27 PHP8の機能を使って コードを書いてみる

Slide 28

Slide 28 text

© 2012-2024 BASE, Inc. 28 ● Blogの投稿内容を管理するオブジェクト ● statusはdraft、published、archived の3つのステータスが存在するが、 setStatusメソッド内で管理している ● setStatus内では、期待してないステー タスが来た場合に例外を投げる PHP8の機能を使わないパターン title = $title; $this->content = $content; $this->setStatus($status); } public function setStatus($status) { if (!in_array($status, ['draft', 'published', 'archived'])) { throw new InvalidArgumentException('Invalid status'); } $this->status = $status; } public function getStatus(): string { return $this->status; }

Slide 29

Slide 29 text

© 2012-2024 BASE, Inc. 29 title = $title; $this->content = $content; $this->setStatus($status); } public function setStatus($status) if (!in_array($status, ['draft', 'published', 'archived'])) { throw new InvalidArgumentException('Invalid status'); } $this->status = $status; } public function getStatus(): string { return $this->status; } // 実行イメージ $blog = new BlogPost( title: 'New blog post', content: 'This is the content of the blog post.', status: PostStatus::Draft ); var_dump($blog->getStatus()); // 'draft' $blog->setStatus('published'); var_dump($blog->getStatus()); // 'published' PHP8の機能を使わないパターン

Slide 30

Slide 30 text

© 2012-2024 BASE, Inc. 30 どこに問題があるか? PHP8の機能を使わないパターン title = $title; $this->content = $content; $this->setStatus($status); } public function setStatus($status) { if (!in_array($status, ['draft', 'published', 'archived'])) { throw new InvalidArgumentException('Invalid status'); } $this->status = $status; } public function getStatus(): string { return $this->status; }

Slide 31

Slide 31 text

© 2012-2024 BASE, Inc. title = $title; $this->content = $content; $this->setStatus($status); } public function setStatus($status) { if (!in_array($status, ['draft', 'published', 'archived'])) { throw new InvalidArgumentException('Invalid status'); } $this->status = $status; } public function getStatus(): string { return $this->status; } 31 ● 🤔変数が増えてきたら、その分コンス トラクタに渡す値が増えそう PHP8の機能を使わないパターン

Slide 32

Slide 32 text

© 2012-2024 BASE, Inc. title = $title; $this->content = $content; $this->setStatus($status); } public function setStatus($status) { if (!in_array($status, ['draft', 'published', 'archived'])) { throw new InvalidArgumentException('Invalid status'); } $this->status = $status; } public function getStatus(): string { return $this->status; } 32 PHP8の機能を使わないパターン ● 🤔変数が増えてきたら、その分コンス トラクタに渡す値が増えそう ● 🤔setStatus内では in_array を使って 判定しているが、第三引数にtrueをいれ ない限りは厳密な型比較を行わない。 ● 🤔statusが増えてきたらその分、 in_arrayの第2引数の配列に値を追加す る必要がある

Slide 33

Slide 33 text

© 2012-2024 BASE, Inc. 33 PHP8.0 (2020/11/26) ● 名前付き引数 ● Attribute ● Constructor Property Promotion ● Match 式 ● Union 型 ● Nullsafe 演算子 など PHP8.1 (2021/11/25) ● Enum型 ● 読み取り専用プロパティ ● 交差型 ● Never型 など PHP8.2(2022/12/08 ) ● 読み取り専用クラス ● Random 拡張モジュール ● Never型 など ● null, false, true が、独立 した型に ● 動的なプロパティが非推奨 に など PHP8の機能を使うパターン

Slide 34

Slide 34 text

© 2012-2024 BASE, Inc. status = $status; } public function setStatus(PostStatus $status): void { $this->status = $status; } } public function getStatus(): string { return $this->status; } 34 ● 😊 Enum型を導入することでstatusプロパティ が取り得る値をdraft、published、archivedの みに限定した。これにより、無効な値が設定さ れることを防ぎ、コードの安全性を向上させま す PHP8の機能を使うパターン

Slide 35

Slide 35 text

© 2012-2024 BASE, Inc. status = $status; } public function setStatus(PostStatus $status): void { $this->status = $status; } } public function getStatus(): string { return $this->status; } 35 ● 😊 Enum型を導入することでstatusプロパティ が取り得る値をdraft、published、archivedの みに限定した。これにより、無効な値が設定さ れることを防ぎ、コードの安全性を向上させま す ● 😊 titleとcontentプロパティをread onlyとし て宣言することで、これらのプロパティが初期 化後に変更されないことを保証する PHP8の機能を使うパターン

Slide 36

Slide 36 text

© 2012-2024 BASE, Inc. status = $status; } public function setStatus(PostStatus $status): void { $this->status = $status; } } public function getStatus(): string { return $this->status; } 36 ● 😊 Enum型を導入することでstatusプロパティ が取り得る値をdraft、published、archivedの みに限定した。これにより、無効な値が設定さ れることを防ぎ、コードの安全性を向上させま す ● 😊 titleとcontentプロパティをread onlyとし て宣言することで、これらのプロパティが初期 化後に変更されないことを保証する ● 😊 setStatusは引数にEnum型 のPostStatusを 指定する事で、Enumに定義してない値は型で弾 く事ができる。加えて定義を追加するのは PostStatusだけで良くなります。 PHP8の機能を使うパターン

Slide 37

Slide 37 text

© 2012-2024 BASE, Inc. 37 status = $status; } public function setStatus(PostStatus $status): void { $this->status = $status; } } public function getStatus(): string { return $this->status; } // 実行イメージ $blog = new BlogPost( title: 'New blog post', content: 'This is the content of the blog post.', status: PostStatus::Draft ); var_dump($blog->getStatus()->value); // 'draft' $blog->setStatus(PostStatus::Published); var_dump($blog->getStatus()->value); // 'published' PHP8の機能を使うパターン

Slide 38

Slide 38 text

© 2012-2023 BASE, Inc. 38 まとめ

Slide 39

Slide 39 text

© 2012-2024 BASE, Inc. まとめ 39 ● 型指定は当然だが、Enum型、match式、Readonly Properties が登場し た事でより安全にかつ、シンプルにコードを書けるようになっている。 ○ “「出来てはならぬことを禁じる」のではなく、はじめから「出来ていい ことだけを出来るようにする」と考える” ● PHP8の機能を使わなくも堅牢なコードを書けるが、より使いやすくなっ ていると感じる。 ○ 開発者が意識しなくても機能を使う事で堅牢な状態を実現できる ● まだまだPHP8.xはこれからバージョンアップするので、堅牢な状態を意 識してコードを書いていきましょう!

Slide 40

Slide 40 text

© 2012-2024 BASE, Inc. 40 Thanks for listening ! Enjoy PHPerKaigi2024!

Slide 41

Slide 41 text

© 2012-2023 BASE, Inc. 41 参考資料

Slide 42

Slide 42 text

© 2012-2024 BASE, Inc. 42 ● PHPConference2016 Track1 (3) PHP7で堅牢なコードを書く ● PHPerKaigi 2022: 予防に勝る防御なし - 堅牢なコードを導く様々な設計の ヒント ● https://blog.shin1x1.com/entry/impression-of-php8-new-features ● https://qiita.com/kakiyuta/items/5de76509337ea40c19e3 ● https://kojirooooocks.hatenablog.com/entry/2021/01/08/004707 ● https://qiita.com/blue32a/items/91bb1b57b92aa1a5a377 ● https://kinsta.com/jp/blog/php-8 スライドを作るにあたって参考にさせて頂きました。 ありがとうございました!!