GMOSSPのPHP7.2へのバージョンアップを行いました。

このエントリーは、GMOアドマーケティング Advent Calendar 2018 の 【12/2】 の記事です。
GMOアドマーケティングとしては初のAdvent Calendar参戦です。

はじめに

こんにちは。
18年新卒で入社いたしました、GMOアドマーケティングのK.Kです。

新卒研修を終え、現在はゴリゴリ業務に取り組んでいます。

今回の記事では、弊社のプロジェクトGMOSSPのPHPのバージョンを、PHP7.0からPHP 7.2にバージョンアップしましたので、バージョンアップの際の対応内容に関してご紹介させていただきます。

php
(引用元|https://secure.php.net/download-logos.php


目次

  1. 対応方針
  2. 対応内容
  3. 下位互換性のない変更点について
    3-1. rand() (PHP7.1_incompatible)
    3-2. 科学記法に対応 (PHP7.1_incompatible)
    3-3. 文字列における空のインデックス演算子 (PHP7.1_incompatible)
    3-4. trait のプロパティの値チェック(PHP7.2_incompatible)
    3-5. json_decode() 関数のオプション(PHP7.2_incompatible)
    3-6. countabe ではない型をカウントしたときの警告(PHP7.2_incompatible)
  4. 推奨されなくなる機能について
    4-1. mcrypt (PHP7.1_deprecated)
    4-2. each関数 (PHP7.2_deprecated)
    4-3. クオートしない文字列(PHP7.2_deprecated)
  5. CodeIgniterのバージョンアップ
  6. 最後に

対応方針

バージョンアップの対応方針です。
今回は以下の理由から、慎重に下位互換性のない変更点(incompatible)、推奨されなくなる機能(deprecated)共に全範囲対応し、PHP7.0との後方互換性を維持しながらの対応を行うこととなりました。

  • マイナーバージョンアップである
  • サービスに影響する対応箇所が多く、サービスを止めずにバージョンを上げる必要がある
  • 他にもサービス改善のプロジェクトが進行している

対応内容

実際の対応内容になります。

影響範囲の調査、対応

影響範囲の調査を行い、必要に応じて、詳細調査を行いました。
実際には対応不要のケースもありましたが、調査範囲が多かったのでかなり苦労しました。

PHPUnit, PHP CS Fixerのバージョンアップ

GMOSSPのCIの概要に関しては、こちら
CircleCIのDockerイメージを変更する必要があることと、PHP CS fixerに@PHP71Migrationというルールがあり活用しようとしたため、CIで導入しているパッケージのバージョンアップを優先して行いました。

composerパッケージの影響調査とバージョンアップの検討

必要に応じてcomposerパッケージのバージョンアップを検討しました。
今回の場合、codeigniter/frameworkgoogle/cloudのバージョンアップを行いました。
codeigniter/frameworkに関しては詳細は後述いたします。
google/cloudに関しては、google/cloud依存ライブラリのguzzlehttp/guzzleにてPHP7.2のcount()に関する変更でwarningが出るバグがあったので、バージョンアップしました。


下位互換性のない変更点について

基本的な下位互換性のない変更点に関しては以下に記載があります。

URLを貼るだけでは味気がないので、今回はアウトプットとしていくつか、PHPのバージョンの違いによる挙動の変更などを紹介いたします。

rand() (PHP7.1_incompatible)

PHP7.1の変更でrand()/srand()関数がそれぞれmt_rand()/mt_srand()のエイリアスとなっています。
つまり同じseed値でrand()、mt_rand()を利用しても同じ結果が返ってきます。そのため適切な再初期化をしていく必要があります。

科学記法に対応 (PHP7.1_incompatible)

そもそも科学記法とはについてはググっていただけると。
文字列でもキャストしてくれるようになりましたという変更です。

文字列における空のインデックス演算子 (PHP7.1_incompatible)

PHPは$str[0]などとすれば、文字列内のの任意の文字へのアクセスができます。($str[0]は1文字目)
PHP7.0までは空の文字列に空のインデックス演算子を適用すると配列に変換されていましたが、こちらがバージョンアップでエラーとなります。

他にも7.0から7.1への下位互換性のない変更点では未完成のオブジェクトのデストラクタは呼び出されなくなったりしているので、デストラクタが呼ばれなくても問題ないかなどの検証も行なっていきました。

trait のプロパティの値チェック(PHP7.2_incompatible)

使用クラスでトレイトと同じ名前のプロパティの比較を7.2までは(1 == true)で行なっていました。
この比較が厳密になり、Fatal Errorが出るようになりました。

json_decode() 関数のオプション(PHP7.2_incompatible)

json_decode()のオプションJSON_OBJECT_AS_ARRAYが第二引数がnullの時に適用されるようになり、挙動が変わっています。

countabe ではない型をカウントしたときの警告(PHP7.2_incompatible)

配列、もしくはCountaleインターフェースを実装していないオブジェクト以外はcount()でWarningが出るようになりました。
Warningを避けるためにはis_array()を用いてあげるのが良いのではないでしょうか。


推奨されなくなる機能について

PHP7.1で推奨されなくなる機能
PHP7.2で推奨されなくなる機能

mcrypt (PHP7.1_deprecated)

拡張モジュールmcryptがdepricateになっています。OpenSSLもしくはSodiumの使用が推奨されています。
PHP7.2からはPECLに移っています。

each関数 (PHP7.2_deprecated)

7.2へのバージョンアップでeach関数がdeprecateとなります。
今までwhile, list, each, nextを利用していい感じにポインターを保持した状態でforeachのように使用することができました。
割と特殊なケースなのでサンプル割愛です。2つの配列をポインタをずらしながら条件によって精査し、余った配列を回す時とかです。
$i++のようにカウンターを用いるのが良いかと思います。

クオートしない文字列(PHP7.2_deprecated)

文字列をクオートしない時のエラーレベルが変更されています。

今までcontinueやbreakなどのキーワードにタイプミスがあった時に、文字列として扱ってNoticeレベルでエラーが出ていました。
error_reportingのレベルでNoticeを非表示にしていると気づかないエラーですが、それによって期待通りの挙動にならないことがあります。


CodeIgniterのバージョンアップ

CodeIgniterのバージョンアップ方法に関しては公式ドキュメントのこちらに記載されてあります。
PHP7.1およびPHP7.2とのバージョンの互換性によりバージョンアップ対応する必要があります。

ファイルセッションドライバ

PHP7.1のバージョンアップでセッションIDの生成に関する変更があります。
これによりCodeIgniterのバージョン3.1.1以下に影響があり、ファイルセッションドライバが動かなくなります。
Sessionがすぐ切れるという挙動が起きるので、気付きやすいです。

CodeIgniter Change Log

Version 3.1.2
Fixed a regression (#4874) – Session Library didn’t take into account session.hash_bits_per_character when validating session IDs.

(引用元|https://www.codeigniter.com/user_guide/changelog.html#bug-fixes-for-3-1-2

メールバリデーション

PHP7.2へのバージョンアップで推奨されなくなる機能にINTL_IDNA_VARIANT_2003 バリアントがあります。
CodeIgniterのForm_validationライブラリのメールのバリデーション、Emailライブラリでidn_to_ascii()を用いていたため、depricateが出ます。

CodeIgniter Change Log

Version 3.1.7
Updated Form Validation Library rule valid_email to use INTL_IDNA_VARIANT_UTS46 for non-ASCII domain names.
Updated Email Library to use INTL_IDNA_VARIANT_UTS46 for non-ASCII domain names.
Version 3.1.8
Fixed a bug where Form Validation Library, Email Library tried to use INTL_IDNA_VARIANT_UTS46 when it was undeclared.

(引用元|https://www.codeigniter.com/user_guide/changelog.html#version-3-1-7https://www.codeigniter.com/user_guide/changelog.html#bug-fixes-for-3-1-8

とあり、解消されていることが確認できます。


最後に

今回初めてバージョンアップ対応を行いました。


(GitHubのバージョンアップに関するプルリクエストの一部です。頑張りました。)

非効率だったかもしれませんが、一つ一つ調査を行い、対応したことによって、PHP、Docker、CodeIgniter、google/cloudなど多くの知識を得ながらタスクを消化していくことができました。
バージョンアップに関しての挙動や、日本語ドキュメントが充実していなかったこともあり手惑いましたが、やりきったことはかなりの達成感です。

明日は、S.Rさんの「Spark 並列化チューニングの一例」についてのお話です。
お楽しみに。

クリスマスまで続くGMOアドマーケティング Advent Calendar 2018
ぜひ今後も投稿をウォッチしてください!

■エンジニアによるTechblog公開中!
https://techblog.gmo-ap.jp/
■Wantedlyページ ~ブログや求人を公開中!~
https://www.wantedly.com/projects/199431
■エンジニア採用ページ ~福利厚生や各種制度のご案内はこちら~
https://www.gmo-ap.jp/engineer/
■エンジニア学生インターン募集中! ~有償型インターンで開発現場を体験しよう~
https://hrmos.co/pages/gmo-ap/jobs/0000027