Upgrade to Pro — share decks privately, control downloads, hide ads and more …

今だから話せるPHP8バージョンアップの裏側~全5サービスの事例紹介~

MasaKu
April 10, 2022

 今だから話せるPHP8バージョンアップの裏側~全5サービスの事例紹介~

2022/04/10 PHPerKaigi 2022

MasaKu

April 10, 2022
Tweet

More Decks by MasaKu

Other Decks in Technology

Transcript

  1. #phperkaigi PHP7.4 の新機能 • 型付きプロパティ • Preload ◦ opcache に事前ロードするス

    クリプトを指定可能 class User { public int $id; public string $name; } • アロー関数 $y = 1; // PHP7.4 で動作 $fn1 = fn($x) => $x + $y; // PHP7.4 以前で上記と等価 $fn2 = function ($x) use ($y) { return $x + $y; }; 6
  2. #phperkaigi PHP8.0 の新機能 • 名前付き引数 • コンストラクタの プロパティ昇格 myFunction(paramName: $value);

    array_foobar(array: $value); • UNION型 • match式 class Point { public function __construct( public float $x = 0.0, public float $y = 0.0, public float $z = 0.0, ) {} } class Number { public function __construct( private int|float $number ) {} } echo match (8.0) { '8.0' => "マッチしない", 8.0 => "マッチする", }; 7
  3. #phperkaigi 下位互換性のない変更点 • ChangeLog で確認できた件数 ◦ PHP8 のChangeLogの件数が多い ▪ レガシーコードにおいてインパクトが大きい変更も含まれる

    PHPバージョン ChangeLogの件数 7.4 27 8.0 166 インパクトの大きい変更 ① == による緩やかな比較の挙動変更 ② 新たなエラー(ValueError)の追加 ③ 標準関数の引数の型が厳密化 9
  4. #phperkaigi 緩やかな比較を行う処理への影響 • 演算子 ◦ ==、!=、>、>=、<、<=、<=> • 関数 ◦ in_array()、array_search()、array_keys()

    ▪ strict=true でない場合 • ソート ◦ sort()、rsort()、asort()、arsort()、array_multisort() ▪ SORT_REGULAR を渡した場合 • switch文 11
  5. #phperkaigi プログラム修正 • 影響ありとなった箇所の修正 ◦ Error になる箇所 ▪ クラス名と同じ名前のメソッドを __construct()に置き換え

    ▪ ラップ関数で置き換え, など ◦ Warning になる箇所 ▪ 以下の値が未定義の状態で呼び出されている箇所の修正 • 変数 • 配列のキー 19
  6. #phperkaigi • 歴史の浅いサービス ◦ Laravel が利用されており仕組みを工夫して対応 ▪ データの入出力箇所で型をチェックするようにする • Laravel

    の Requestクラスのバリデーションルールを元に 自動的にキャストする仕組などを導入 • 歴史の長いサービス ◦ レガシーコードが混在し複雑化していて仕組みでは対応できない ▪ 曖昧さを寛容に受け入れていた時代のPHPでバリバリ活躍 • しらみつぶしな力技で対応 各サービスの特徴を考慮した修正 20
  7. #phperkaigi テスト実施戦略 • 修正が必要なことが明らかな箇所 ◦ 事前調査で修正した箇所 ▪ 単体テスト • 修正が必要だが調査しきれていない箇所

    ◦ 事前調査で修正が漏れている可能性のある箇所の洗い出し ▪ 全機能テスト ◦ 顧客の重要業務において不具合が発生していないかの確認 ▪ 重要機能テスト 21
  8. #phperkaigi オフショアチームとの作業の進め方 • 作業ボリュームが大きく作業内容が明確なタスクを依頼 ◦ 作業依頼のポイント ▪ 依頼する作業は一覧化して認識齟齬が生まれないようにする ▪ 調査手順を明確にする

    • フォーマットを提供して入力してもらうだけにする等 ◦ コミュニケーションのポイント ▪ 調査や対応の方針が決められない場合は一緒に検討する • 調査不可能なほど影響箇所がある場合の対応方針など ▪ 疑問点があればすぐに共有してもらうようにする 25
  9. #phperkaigi その他の作業 • リリースまでのマイナーバージョンの監視 ◦ PHP8 バージョンアップの対応は長期間に渡る ▪ 新しいマイナーバージョンがリリースされていないかを確認 •

    PhpStorm のサポートバージョン確認 ◦ 古いPhpStorm を利用している方(ライセンス契約上)が対象 ▪ PhpStormのバージョンが古くPHP8に対応していない場合は バージョンアップ 26
  10. #phperkaigi リリース後に見つかった不具合① • デフォルト設定を変更すると特定の画面が表示できなくなる ◦ デフォルト設定が変更されることで内部処理にて 0 == “” の比較が発生

    ▪ 条件分岐の結果が反転 ▪ 以降の処理でValueErrorが発生 • バグ原因:「緩やかな比較の挙動変更」 ◦ プロダクトコード全体の 0 == “” の箇所は調査しきれていない ▪ ソースの調査では影響箇所を洗い出しにくい ◦ 全機能テスト/重要機能テストで拾いたかった ▪ 全てのデフォルト設定を変更したテストは考慮できていなかった 28
  11. #phperkaigi リリース後に見つかった不具合② • 文字列のパース処理が想定外の結果になり TypeError が発生 ◦ 配列としてパースされるパターンの考慮漏れ ▪ 文字列型を期待する標準関数に配列型が渡りTypeErrorが発生

    • バグ原因:「想定外の箇所でTypeErrorが出力された」 ◦ テストで全てのパターンを網羅することはできない ▪ エラー処理をしっかりと見直しておくべきだった 29
  12. #phperkaigi リリース後に見つかった不具合③ • エラーハンドリングできなくなっていた 30 try {
 $array = null;


    $arrayCount = count($array);
 if ($arrayCount <= 0) {
 throw new Exception('想定外の値が挿入された');
 }
 } catch (Exception $e) {
 echo $e->getMessage();
 }
 PHP8 以前 「想定外の値が挿入された」と 出力 PHP8 以降 Fatal error が発生
  13. #phperkaigi リリース後に見つかった不具合③ • バグ原因の詳細 ◦ Warning が発生していた箇所 ▪ PHP8 以前:後続処理で

    Exception を検知 ▪ PHP8 以降:TypeErrorが発生 • TypeError は Error のため Exceptionでは catch が処理されない • バグ原因:「ハンドリングするエラーの考慮不足」 ◦ TypeError が発生する可能性がある箇所はテストで拾い上げたかった ▪ しかし、すべてのパターンを網羅するは難しい ◦ 想定外のパターンを考慮して例外処理は見直しておくべきだった 31
  14. #phperkaigi 不具合発見後の対応 • 類似バグが他の箇所でも発生しないかを確認 ◦ テストで拾えなかった=漏れやすい観点 ▪ 可能な限り影響調査 • 不具合内容はすぐに他サービスにも共有

    ◦ いずれかのチームで拾えなかった観点は他サービスも盲点 ◦ 必要に応じて他サービスも追加調査 ▪ 大半はソース上の調査は難しいものばかり • ValueError や TypeError はソース上の調査では分かりづらい 32
  15. #phperkaigi PHP8 バージョンアップ対応のふりかえり • 不具合はいくつか発生したがサービスを止めることなく稼働 ◦ PHPのバージョンを切り戻すなどの大きな対応は取らずに済んだ ▪ 概ねPHP8 バージョンアップは成功したという認識

    • 要因 ◦ 基本的な調査が十分できていた ◦ 品質担保のテストが十分に実施できていた ◦ リリース後に見つかった不具合も速やかに修正してリリースできた 34
  16. #phperkaigi 過去のPHP対応工数との比較 • 弊社の全PHPサービスの PHP8 バージョンアップの工数 ◦ PHP7.1 から PHP7.3

    へのバージョンアップの対応工数の 約5倍 ▪ サービスによっては 約10倍 の対応工数がかかった ▪ PHP8 がいかに大きな変更だったかがわかる PHP5.6 → PHP7.1 PHP7.1 → PHP7.3 PHP7.3 → PHP8.0 ※8.7人月 8.2人月 42.1人月 ※PHP5.6 → PHP7.1のバージョンアップの工数には  1サービス分の工数が含まれていません 35 弊社の全PHPサービスの合計工数
  17. #phperkaigi まとめ • PHP7.3 系から PHP8.0 へのバージョンアップを実施 • 5サービスごとの対応工数は PHP7.1

    → PHP7.3 と比較して 3倍~10倍だった • リリース後にいくつかの不具合が発生したが大きな問題も無く対応 が完了 ◦ PHP8バージョンアップは概ね成功という形で終えることができた 36
  18. #phperkaigi 最後に • PHP8 バージョンアップの代表者へのヒアリングで出た意見 ◦ 近年のPHPは安全性を高める(型を意識した)変更が立て続けに導入されて いるが、今回はかなり思い切ったバージョンアップという印象 ◦ 様々な新機能を使えるようになるのが楽しみ

    • 私の所感 ◦ 対応が完了するまでは下位互換性のない変更と真摯に向き合い 対応完了後は新機能を取り入れようとする思考に切り替えていく ▪ セキュリティサポートを得ることだけを目的と捉えない 37
  19. #phperkaigi 参考資料 • PHP Conference 2021, 「レガシーシステムにおけるPHP8バージョンアップのアプリ対応記」 ◦ https://speakerdeck.com/bosshawk/regasisisutemuniokeruphp8baziyonatupufalseapuridui-ying-ji-lu-ad4444bf-51f5-4379-86c3-cddb38163a3c ,

    (参照 2022-03-23) • PHP Conference 2021, 「20年モノの巨大Webサービスの開発継続戦略 - ミドルウェアのバージョンアップとの向き合い方」 ◦ https://speakerdeck.com/penguin045/20nian-mofalsefalseju-da-websabisufalsekai-fa-ji-sok-zhan-lue-midoruueafalsebaziyonatuputofalsexiang-ki he-ifang , (参照 2022-03-23) • Rakus Tech Conference 2022, 「息の長いサービスの PHP8バージョンアップで見えた 課題と解決法」 ◦ https://speakerdeck.com/bosshawk/problems-and-solutions-found-when-upgrading-long-term-services-to-php8 , (参照 2022-03-23) • php.net, 「PHP 7.3.x から PHP 7.4.x への移行」 ◦ https://www.php.net/manual/ja/migration74.new-features.php , (参照 2022-03-23) • php.net, 「PHP 7.4.x から PHP 8.0.x への移行」 ◦ https://www.php.net/manual/ja/migration80.new-features.php , (参照 2022-03-23) • qiita, 「【PHP8.0】非厳密な比較演算子`==`の挙動が今さら変更になる」 ◦ https://qiita.com/rana_kualu/items/82cc8295d2102d14b88a , (参照 2022-03-23) 40