Slide 1

Slide 1 text

#phpconf ©2021 RAKUS Co., Ltd. #phpconf レガシーシステムにおける PHP8バージョンアップの アプリ対応記録 2021/10/2 - 2021/10/3 PHP Conference Japan 2021 頓花 貴俊

Slide 2

Slide 2 text

#phpconf 自己紹介 ● 頓花 貴俊 (どんが たかとし) ● 所属 ○ 株式会社 ラクス ○ 販売管理システム【楽楽販売】 ● 技術 ○ メイン:PHP、Javascript、PostgreSQL ○ 経験 :Java、C言語、Fortran

Slide 3

Slide 3 text

#phpconf 目次 ● イントロダクション ● 影響の大きかった主な変更点 ● 課題と対応 ● 今回の対応を振り返って ● 最後に

Slide 4

Slide 4 text

#phpconf 今回、お伝えしたいこと I. 対応時に意識すること A. 全量把握し、対策を練ること B. 品質の担保に対し、費用対効果を考慮したテスト計画を立てるか II. バージョンアップまでに意識すること A. 静的な型を意識した実装を行う B. こまめにリファクタリングする

Slide 5

Slide 5 text

#phpconf イントロダクション 01

Slide 6

Slide 6 text

#phpconf イントロダクション PHP製品の弊社での取り組み 2年 に 1 回 、バージョンアップを実施 ● EOL の 回避 ● サービスの品質担保 上記の両方を満たすために

Slide 7

Slide 7 text

#phpconf イントロダクション 今年EOLを迎える PHP7.3 → PHP8.0 の バージョンアップを実施 PHP バージョン 初回リリース日 アクティブサポート セキュリティサポート 8.0 2020/11/26 2022/11/26 2023/11/26 7.4 2019/11/28 2021/11/28 2022/11/28 7.3 2018/12/06 2020/12/06 2021/12/06 一つ飛ばし

Slide 8

Slide 8 text

#phpconf イントロダクション 実施前の懸念点 ● (着手当時) 弊社の他商材を含め、 ほかのWebサービスでの実績がほとんどなかった ● リリース日が大きく変更できないため、 開発期間が決まっている ● PHP8.0 で 下位互換性のない変更点 が多数ある

Slide 9

Slide 9 text

#phpconf 影響の大きかった主な変更点 02

Slide 10

Slide 10 text

#phpconf 影響の大きかった主な変更点 ● 緩やかな比較演算子の挙動変更 ● 警告レベルの変更

Slide 11

Slide 11 text

#phpconf 影響の大きかった 主な変更点 緩やかな比較演算子の 挙動変更

Slide 12

Slide 12 text

#phpconf 緩やかな比較 とは PHPでは 厳密な比較 「===」 型まで同じかまで判定する 緩やかな比較「==」 型の相互互換を行った後に判定する 上記が存在します。

Slide 13

Slide 13 text

#phpconf 緩やかな比較演算子の挙動変更 挙動が変わる対象  文字列 と 数値 の 比較 ($int ⇔ $string, $float ⇔ $string) $string : 整数形式 $int ⇔ (int) $string $string : 浮動小数形式 $int ⇔ (float) $string 上記以外 $int ⇔ (int) $string $string : 整数形式 $float ⇔ (float) $string $string : 浮動小数形式 $float ⇔ (float) $string 上記以外 $float ⇔ (float) $string PHP 7.x ※ 左右関係なし

Slide 14

Slide 14 text

#phpconf 緩やかな比較演算子の挙動変更 挙動が変わる対象  文字列 と 数値 の 比較 ($int ⇔ $string, $float ⇔ $string) $string : 整数形式 $int ⇔ (int) $string $string : 浮動小数形式 $int ⇔ (float) $string 上記以外 (string) $int ⇔ $string $string : 整数形式 $float ⇔ (float) $string $string : 浮動小数形式 $float ⇔ (float) $string 上記以外 (string) $float ⇔ $string PHP 8.x ※ 左右関係なし

Slide 15

Slide 15 text

#phpconf 緩やかな比較演算子の挙動変更 まとめると、 対象  文字列 と 数値 の 比較 ($int ⇔ $string, $float ⇔ $string) 事象 文字列側 が 数値形式でない 場合 数値側 が文字列 に変換され、比較結果が 反転 する 条件式 7.x 8.x 0 == "0" TRUE TRUE 0 == "0.0" TRUE TRUE 0 == "foo" TRUE FALSE 0 == "" TRUE FALSE 42 == " 42" TRUE TRUE 42 == "42foo" TRUE FALSE 要注意

Slide 16

Slide 16 text

#phpconf 緩やかな比較演算子の挙動変更 - 関数・式 - ● 演算子 == , != , > , >= , < , <= ● 配列関数 in_array()、array_search()、array_keys() ● ソート関数 sort()、rsort()、asort()、arsort()、array_multisort() ● switch文

Slide 17

Slide 17 text

#phpconf 緩やかな比較演算子の挙動変更 - 具体例 - フォーム から パラメータ が 「””」(空文字) と 数値 で 比較している場合 PHP 7.x (int)“” == 0 ⇒ true PHP 8.x “” == (string) 0 ⇒ false PHP 7.x (int)“” < 1000 ⇒ false PHP 8.x “” < (string) 1000 ⇒ true

Slide 18

Slide 18 text

#phpconf 影響の大きかった 主な変更点 警告レベルの変更

Slide 19

Slide 19 text

#phpconf 警告レベルの変更 ● ERROR に 変更されたエラー ○ 配列関数の引数に配列以外の型を指定 ○ BCMath関数の引数に数値形式以外を指定 ○ implode()の歴史的な問題の削除 ● WARNING に 変更されたエラー ○ 未定義の変数の読み取り ○ 未定義の配列のキーを読み取り ○ 配列でない値のインデックスにアクセス

Slide 20

Slide 20 text

#phpconf 警告レベルの変更 - 具体例 - ● ERROR に 変更されたエラー ○ 配列関数の引数に配列以外の型を指定 ○ BCMath関数の引数に数値形式以外を指定 ○ implode()の歴史的な問題の削除 PHP 7.x ⇒ 出力:10.1 (string) PHP 8.x ⇒ Fatal error PHP 7.x ⇒ 出力:1 (int) PHP 8.x ⇒ Fatal error

Slide 21

Slide 21 text

#phpconf 警告レベルの変更 - 具体例 - ● WARNING に 変更されたエラー ○ 未定義の変数の読み取り ○ 未定義の配列のキーを読み取り ○ 配列でない値のインデックスにアクセス PHP 7.x ⇒ 出力:null PHP 8.x ⇒ 出力:null | Warning

Slide 22

Slide 22 text

#phpconf 課題と対応 04

Slide 23

Slide 23 text

#phpconf 問題の前提 ● PHPの型に寛容であるという特性 ● レガシーなコードを使い続けている状態   → 型チェックをせず、暗黙の型変換を使用してい箇所が多い ⇒ 静的コード解析で影響箇所の調査ができない状態

Slide 24

Slide 24 text

#phpconf 緩やかな比較演算子の挙動変更 - 課題 - 演算子や標準関数を含め 影響箇所 は 約2.7万 → 本来、すべて動作が変わるか確認が必要 (※ アプリ全体のphpコード は 約47万行) ⇒ すべてを 前後関係含めて、チェックは不可能

Slide 25

Slide 25 text

#phpconf 警告レベルの変更 - 課題 - 引数の型や返値の型が宣言されていない箇所が多い → 静的なコード解析が実施できない ⇒ すべてを 前後関係含めて、チェックは不可能

Slide 26

Slide 26 text

#phpconf 対応案 1. 以前と同様の挙動をする関数(ラップ関数)を作成し、 すべての箇所を置き換える 2. すべての箇所を複数パターンでテストを行い、 問題があった箇所を修正する

Slide 27

Slide 27 text

#phpconf 対応案 1. 以前と同様の挙動をする関数(ラップ関数)を作成し、 すべての箇所を置き換える 2. すべての箇所を複数パターンでテストを行い、 問題があった箇所を修正する ⇒ 問題点:新たなコード負債となる ⇒ 問題点:膨大な時間がかかる

Slide 28

Slide 28 text

#phpconf 対応案 1. 以前と同様の挙動をする関数(ラップ関数)を作成し、 すべての箇所を置き換える 2. すべての箇所を複数パターンでテストを行い、 問題があった箇所を修正する ⇒ 問題点:新たなコード負債となる ⇒ 問題点:膨大な時間がかかる

Slide 29

Slide 29 text

#phpconf 今回どのように対応したのか ➢ 演算子に対する対策:修正対象を絞る ➢ 関数に対する対策:チェック関数で調査 緩やかな比較演算子の挙動変更 警告レベルの挙動変更 品質の担保は? ⇒ E2Eテスト・手動テストで確認 ➢ 通過テストで確認

Slide 30

Slide 30 text

#phpconf 今回どのように対応したのか - 実例 - ➢ 修正対象を絞る ○ 比較演算子の結果が変わるパターンから 影響箇所を絞り込み、修正を実施(ラップ関数に変換など) 例) 発見不具合:「””==0」の Boolean値が変わる 0 (定数化含み)と比較しているものリストアップし、 比較側をキャストするように修正 比較1 等号 比較2 v7.3 v8.0 check 0 == 0 => true true 〇 0 == 'abc' => true false × 0 == '' => true false × 0 == true => false false 〇

Slide 31

Slide 31 text

#phpconf ➢ チェック関数で調査 ○ 通過しても動作が変わるか確認できない ■ 引数が正常かチェックする関数を作成 今回どのように対応したのか - 実例 - 例) 発見不具合:「array_key_exist()」第一引数「””」第二引数「0,1,2」の挙動変更 ・第二引数 の 配列内 で 型 が違うもの ・第一引数 の 型 と 第二引数 の 配列の値 の型が違うもの 上記 をチェックし、ログとして出力

Slide 32

Slide 32 text

#phpconf ➢ 通過テストで確認 ○ 変更点はエラーになるので、実際に通過すれば確認可能 今回どのように対応したのか - 実例 -

Slide 33

Slide 33 text

#phpconf 品質の担保 ● 自動テスト ○ E2E テスト・ユニットテストで重要機能をテスト → データパターンが用意されている ● 手動テスト ○ データバリエーションが必要ない箇所のテスト → テストパターンを、「0件, 1件, 複数件」と データが存在しないとき ⇒ 自動テストと手動テストで確認

Slide 34

Slide 34 text

#phpconf 今回の対応を振り返って 05

Slide 35

Slide 35 text

#phpconf 今回の対応を振り返って 一言でいうと、 影響範囲が広い

Slide 36

Slide 36 text

#phpconf 今回の対応を振り返って 影響範囲が広いことへの対策 ターゲットを絞ること ⇒ 品質を担保するには?

Slide 37

Slide 37 text

#phpconf 品質を担保するには? ● カバレッジをどうやって上げるかの観点 ● どこまでテストするのかの観点 ⇒ 品質の担保に対し、費用対効果を考慮したテスト計画を立てる 限られた時間の中で、テストの効果を考慮しテストを計画

Slide 38

Slide 38 text

#phpconf 見つかった不具合 ● 動作テストで発見された不具合 10件程度 ● リリース半年内で発見された不具合 2件 (※ 軽微なもの) → 調査 ・不具合発見時の再調査 ⇒ 全量把握・それに対する検討 により 品質を担保 → チーム内 で 修正方針の検討 なぜ、不具合が少なかったのか?

Slide 39

Slide 39 text

#phpconf 余談 ● 見送りの選択肢は? → 途中、PHP7.4 も選択肢に上がったが 問題の先送りになるだけなのでなんとか対応する方針へ ● 工数は? → 前回のバージョンアップ( PHP7.1 → PHP7.3) 時の 2 倍 以上

Slide 40

Slide 40 text

#phpconf これからのバージョンアップに向けて ● ミドルウェアの更新で使用可能 ● 通常のリリース毎のデグレチェック ➢ 自動テストを追加する メリット

Slide 41

Slide 41 text

#phpconf これからのバージョンアップに向けて テストが必要な対象画面の自動テストの作成には 手動テスト 実施工数 の 約 5 倍 かかる想定 デメリット → どのテストケースを自動化するのか ⇒ 見極めが必要 ➢ 自動テストを追加する ● コストが高い ⇒ 今回は作成コストには合わない、手動テスト実施

Slide 42

Slide 42 text

#phpconf PHPバージョンアップの今後 ● 推奨されない宣言・関数の削除 ● 型の制限の強化 ● エラーレベルの変更 ⇒ 新規コード:静的な型を意識した実装を行う ⇒ 既存コード:コード負債は小まめにリファクタリングする

Slide 43

Slide 43 text

#phpconf 最後に 05

Slide 44

Slide 44 text

#phpconf 今回、お伝えしたいこと I. 対応時に意識すること A. 全量把握し、対策を練ること B. 品質の担保に対し、費用対効果を考慮したテスト計画を立てるか II. バージョンアップまでに意識すること A. 静的な型を意識した実装を行う B. 小まめにリファクタリングする

Slide 45

Slide 45 text

#phpconf ご清聴ありがとうございました!