$30 off During Our Annual Pro Sale. View Details »

PHP8.2にバージョンアップして もっと型表現を豊かにしよう

PHP8.2にバージョンアップして もっと型表現を豊かにしよう

PHP8.2にバージョンアップしてもっと型表現を豊かにしよう
PHPカンファレンス沖縄2023 Akito.Tsukahara

PHP8.2からtrue/false型が実装されることはご存知でしょうか?
どのようにPHPの型表現がさらに豊かになったのか紹介させていただきます。

目次
・PHP8.2で新しくできること
・型表現を豊かにしてみよう
・バージョンアップしてみた
・まとめ

AkitoTsukahara

September 15, 2023
Tweet

More Decks by AkitoTsukahara

Other Decks in Programming

Transcript

  1. Copyright© M&Aクラウド
    PHP8.2にバージョンアップして
    もっと型表現を豊かにしよう
    PHPカンファレンス沖縄2023 Akito.Tsukahara

    View Slide

  2. Copyright© M&Aクラウド 2
    ⾃⼰紹介
    塚原彰仁
    AkitoTsukahara
    株式会社M&Aクラウド
    AkitoTsukahara
    akito_tsukahara

    View Slide

  3. Copyright© M&Aクラウド
    この発表でお話しすることは?
    今⽇話すこと
    ● PHP8.2で新しくできること
    ● 型表現を豊かにしてみよう
    ● バージョンアップしてみた
    ● まとめ

    View Slide

  4. Copyright© M&Aクラウド
    PHP8.2で新しくできること
    PHP8.2
    ● 2022/12/08にPHP8.2がリリース🎉

    View Slide

  5. Copyright© M&Aクラウド
    PHP8.2で新しくできること
    新機能💡
    ● true/false/nullが独⽴した型で利⽤可能に
    function alwaysTrue(): true
    {
    return true;
    }
    function alwaysFalse(): false
    {
    return true;
    }
    function alwaysNull(): null
    {
    return null;
    }
    function alwaysTrue(): bool
    {
    return true;
    }
    function alwaysFalse(): bool
    {
    return true;
    }
    function alwaysNull(): ?string //静的解析でエラー
    {
    return null;
    }
    PHP8.2~ ~PHP8.1

    View Slide

  6. Copyright© M&Aクラウド
    PHP8.2で新しくできること
    新機能💡
    ● 選⾔標準形 (Disjunctive Normal Form) 型が使えるように
    public function bar((A&B)|null $entity) {
    return $entity;
    }
    public function bar(mixed $entity) {
    if (
    (($entity instanceof A) &&
    ($entity instanceof B))
    || ($entity === null)
    ) {
    return $entity;
    }
    throw new Exception('Invalid entity');
    }
    PHP8.2~ ~PHP8.1

    View Slide

  7. Copyright© M&Aクラウド
    PHP8.2で新しくできること
    新機能💡
    ● クラスにreadonlyを指定することができるように
    readonly class OkinawaIsland {
    public function __construct(
    public string $name,
    public int $population,
    public int $area,
    ) {
    }
    }
    class OkinawaIsland {
    public function __construct(
    public readonly string $name,
    public readonly int $population,
    public readonly int $area,
    ) {
    }
    }
    PHP8.2~ ~PHP8.1

    View Slide

  8. Copyright© M&Aクラウド
    PHP8.2で新しくできること
    新機能💡
    ● バックトレースにおけるセンシティブなパラメータの出⼒抑制ができる
    function getUser(
    $name,
    $email,
    #[SensitiveParameter] $password
    ) {
    throw new Exception('Error');
    }
    getUser('taro', '[email protected]', 'taropass');
    function getUser(
    $name,
    $email,
    #[SensitiveParameter] $password
    ) {
    throw new Exception('Error');
    }
    getUser('taro', '[email protected]', 'taropass');
    PHP8.2~ ~PHP8.1

    View Slide

  9. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    9

    View Slide

  10. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    その1 Nullオブジェクトパターンで使う👻
    readonly class Speaker {
    public function __construct(
    private Name $name,
    private Email $email,
    private XAccountInterface $xAccount,
    ){}
    public function toArray(): array {
    return [
    'name' => $this->name->getValue(),
    'email' => $this->email->getValue(),
    'x_account' => $this->xAccount->isUndefined()
    ? null : $this->xAccount->getValue(),
    ];
    }
    }
    Speaker.php

    View Slide

  11. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    interface Undefinedable
    {
    public function isDefined(): bool;
    public function isUndefined(): bool;
    }
    その1 Nullオブジェクトパターンで使う👻
    Undefinedable.php
    interface XAccountInterface extends Undefinedable {
    }
    XAccountInterface.php

    View Slide

  12. Copyright© M&Aクラウド
    class UndefinedXAccount extends XAccountInterface {
    public function isDefined(): false {
    return false;
    }
    public function isUndefined(): true {
    return true;
    }
    }
    型表現を豊かにしてみよう
    その1 Nullオブジェクトパターンで使う👻
    class XAccount extends XAccountInterface {
    public function isDefined(): true {
    return true;
    }
    public function isUndefined(): false {
    return false;
    }
    }
    UndefinedXAccount.php
    XAccount.php

    View Slide

  13. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    その2 DNF型で型パズルする(引数)🧩
    interface A {}
    interface B {}
    class ClassAB implements A,B {}
    class TryDNFArgument {
    public function getAandB((A&B) | null $hoge): void {
    echo 'Call getAandB';
    }
    }
    $tryDnfArg = new TryDNFArgument();
    $tryDnfArg->getAandB(new ClassAB()); //Call getAandB
    A&B ⬅ ClassAB OK

    View Slide

  14. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    その2 DNF型で型パズルする(引数)🧩
    interface A {}
    interface B {}
    class ClassAB implements A,B {}
    interface C {}
    class ClassABC implements A,B,C {}
    class TryDNFArgument {
    public function getAandB((A&B) | null $data): void {
    echo 'Call getAandB';
    }
    public function getAB(ClassAB | null $data): void {
    echo 'Call getAB';
    }
    }
    ……
    $tryDnfArg = new TryDNFArgument();
    $tryDnfArg->getAandB(new ClassAB()); //Call getAandB 
    $tryDnfArg->getAB(new ClassAB()); //Call getAB
    $tryDnfArg->getAandB(new ClassABC()); //Call getAandB
    $tryDnfArg->getAB(new ClassABC()); //Fatal Error
    サンプルコード
    引数の場合は、
    A&B ⬅ ClassABC OK
    ClassAB ⬅ ClassABC Error

    View Slide

  15. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    その2 DNF型で型パズルする(引数)🧩
    A
    泳げる
    インターフェース
    B
    えらで呼吸
    インターフェース
    A
    泳げる
    インターフェース
    A&B
    泳げて
    水中で呼吸できる
    C
    魚類

    View Slide

  16. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    その2 DNF型で型パズルする(引数)🧩
    A
    泳げる
    インターフェース
    B
    えらで呼吸
    インターフェース
    C
    肺で呼吸
    インターフェース
    A&B
    泳げて
    水中で呼吸できる
    C
    魚類

    View Slide

  17. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    その2 DNF型で型パズルする(引数)🧩
    A
    泳げる
    B
    えらで呼吸
    C
    肺で呼吸
    A&B
    泳げて
    水中で呼吸
    より広い型を受け入れられる
    反変性
    ※DNF型だから反変性を持つ訳ではなく、型表現の幅
    が広がるという意味です。
    「共変性と反変性」の完全サポートはPHP7.4から

    View Slide

  18. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    その2 DNF型で型パズルする(戻り値)🧩
    interface A {}
    interface B {
    function callB(): void;
    }
    class ClassAB implements A,B {
    function callB(): void {
    var_dump('callB');
    }
    }
    class TryDNFReturnValue {
    public function getAandB(): (A&B)| null {
    return new ClassAB();
    }
    }
    ……
    $tryDnfRV = new TryDNFReturnValue();
    $tryDnfRV->getAandB()?->callB(); //CallB

    View Slide

  19. Copyright© M&Aクラウド
    ……
    class TryDNFReturnValue {
    public function getAandB(): (A&B)| null {
    return new ClassABC();
    }
    }
    $tryDnfRV = new TryDNFReturnValue();
    $tryDnfRV->getAandB()?->callB(); //CallB
    $tryDnfRV->getAandB()?->callC(); //CallC
    型表現を豊かにしてみよう
    interface B {
    function callB(): void;
    }
    interface C {
    function callC(): void;
    }
    class ClassABC implements A,B,C {
    function callB(): void {
    var_dump('callB');
    }
    function callC(): void {
    var_dump('callC');
    }
    }
    その2 DNF型で型パズルする(戻り値)🧩
    ただしPHPStanではエラーになる。
    Call to an undefined method A&B::callC().
    サンプルコード

    View Slide

  20. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    その2 DNF型で型パズルする(戻り値)🧩
    会場までの
    行き方ガイド
    A&B&C&D
    A
    飛行機
    インターフェース
    B
    モノレール
    インターフェース
    C
    バス
    インターフェース
    D
    徒歩
    インターフェース
    羽田からの
    案内が記載
    ないちゃー

    View Slide

  21. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    その2 DNF型で型パズルする(戻り値)🧩
    会場までの
    行き方ガイド
    B&C&D
    A
    飛行機
    インターフェース
    B
    モノレール
    インターフェース
    C
    バス
    インターフェース
    D
    徒歩
    インターフェース

    羽田からの
    案内は不要
    うちなーんちゅ

    View Slide

  22. Copyright© M&Aクラウド
    型表現を豊かにしてみよう
    その2 DNF型で型パズルする(戻り値)🧩
    会場までの
    行き方ガイド
    ❌ 受け入れる型を絞る
    共変性
    ※DNF型だから共変性を持つ訳ではなく、型表現の幅
    が広がるという意味です。
    「共変性と反変性」の完全サポートはPHP7.4から

    View Slide

  23. Copyright© M&Aクラウド
    バージョンアップしてみた
    23

    View Slide

  24. Copyright© M&Aクラウド
    よし!バージョンアップだ!
    ● PHP8.1からのアップデートだし、⼤きな差分はないのでは?
    ● バージョンを上げてみて、テストを動かしてみる!!
    ○ ?⾝に覚えのない箇所でエラーがちらほら?
    バージョンアップしてみた

    View Slide

  25. Copyright© M&Aクラウド
    バージョンアップしてみた
    function calcDay(int $timestamp, int $day){
    date_default_timezone_set('Asia/Tokyo');
    $calcTimestamp = strtotime(date('Y-m-d H:i:s', $timestamp) . sprintf('+%s day', $day));
    echo date('Y-m-d H:i:s',$calcTimestamp);
    }
    $phpカンファレンス沖縄
    2023当日 = 1694790000; //'2023-09-16 00:00:00';
    calcDay($phpカンファレンス沖縄
    2023当日, -3);
    ここで問題です!
    ● 以下の処理の実⾏結果はどうなる?(~PHP8.1)
    ~PHP8.1

    View Slide

  26. Copyright© M&Aクラウド
    バージョンアップしてみた
    function calcDay(int $timestamp, int $day){
    date_default_timezone_set('Asia/Tokyo');
    $calcTimestamp = strtotime(date('Y-m-d H:i:s', $timestamp) . sprintf('+%s day', $day));
    echo date('Y-m-d H:i:s',$calcTimestamp);
    }
    $phpカンファレンス沖縄
    2023当日 = 1694790000; //'2023-09-16 00:00:00';
    calcDay($phpカンファレンス沖縄
    2023当日, -3);
    結果は...
    2023-09-13 00:00:00
    ~PHP8.1

    View Slide

  27. Copyright© M&Aクラウド
    バージョンアップしてみた
    function calcDay(int $timestamp, int $day){
    date_default_timezone_set('Asia/Tokyo');
    $calcTimestamp = strtotime(date('Y-m-d H:i:s', $timestamp) . sprintf('+%s day', $day));
    echo date('Y-m-d H:i:s',$calcTimestamp);
    }
    $phpカンファレンス沖縄
    2023当日 = 1694790000; //'2023-09-16 00:00:00';
    calcDay($phpカンファレンス沖縄
    2023当日, -3);
    さらにもう⼀問!
    ● 以下の処理の実⾏結果はどうなる?(PHP8.2~)
    PHP8.2~

    View Slide

  28. Copyright© M&Aクラウド
    バージョンアップしてみた
    function calcDay(int $timestamp, int $day){
    date_default_timezone_set('Asia/Tokyo');
    $calcTimestamp = strtotime(date('Y-m-d H:i:s', $timestamp) . sprintf('+%s day', $day));
    echo date('Y-m-d H:i:s',$calcTimestamp);
    }
    $phpカンファレンス沖縄
    2023当日 = 1694790000; //'2023-09-16 00:00:00';
    calcDay($phpカンファレンス沖縄
    2023当日, -3);
    結果は...
    2023-09-19 00:00:00
    PHP8.2~
    サンプルコード

    View Slide

  29. Copyright© M&Aクラウド
    バージョンアップしてみた
    原因はどこなんだ...👀

    View Slide

  30. Copyright© M&Aクラウド
    バージョンアップしてみた
    function calcDay(string $timestamp, int $day){
    date_default_timezone_set('Asia/Tokyo');
    $calcTimestamp = strtotime(date('Y-m-d H:i:s', $timestamp) . sprintf('+%s day', $day));
    echo date('Y-m-d H:i:s',$calcTimestamp);
    }
    $phpカンファレンス沖縄
    2023当日 = 1694790000; //'2023-09-16 00:00:00';
    calcDay($phpカンファレンス沖縄
    2023当日, -3);
    おやおや...🤔
    PHP8.2~
    +-3 day

    View Slide

  31. Copyright© M&Aクラウド
    バージョンアップしてみた
    つまりどうなるのか?🙄
    +-3 day
    PHP8.2以降は
    「+3 day」として処理される
    PHP8.2以前は
    「-3 day」として処理される

    View Slide

  32. Copyright© M&Aクラウド
    バージョンアップしてみた
    下位互換性のない変更点は要チェック👀

    View Slide

  33. Copyright© M&Aクラウド
    おまけ
    33

    View Slide

  34. Copyright© M&Aクラウド
    おまけ
    もうすぐPHP8.3リリースですね🙌
    ● 予定通り⾏けば 2023/11/23 リリース予定

    View Slide

  35. Copyright© M&Aクラウド
    まとめ
    35

    View Slide

  36. Copyright© M&Aクラウド
    まとめ
    ● PHP8.2から新しく実装機能がたくさん
    ● PHPのバージョンを上げて、型表現を豊かにしよう
    ○ true/false/nullが独⽴した型で使える
    ○ 選⾔標準形 (Disjunctive Normal Form) 型が使える
    ● バージョンを上げる時には「下位互換性のない変更点」をチェック
    ● もうすぐPHP8.3がリリースされる

    View Slide

  37. Copyright© M&Aクラウド
    参考資料
    ● https://www.php.net/releases/8.2/ja.php
    ● https://www.prime-strategy.co.jp/column/archives/column_5253
    ● https://qiita.com/rana_kualu/items/fc4b02e2daaf102aa92f
    ● https://www.cyberer.net/2020/03/covariant-contravariant.html
    ● https://www.php.net/manual/ja/language.oop5.variance.php
    ● https://zukan.com/fish/internal2961

    View Slide

  38. Copyright© M&Aクラウド
    ありがとうございました!
    38

    View Slide