ランサーズ等のサービスを開発・運用する中で得た知識やノウハウを紹介しています。

PHP5.3→5.6移行が完了しました

SREチームの金澤です。

PHP5.3→5.6バージョンアップが完了しましたので報告いたします。

CakePHP1.3→2.8バージョンアップが完了してから約2カ月での移行となりました。

2019/03/20にコネヒトさんで開催されたPHP勉強会で、その詳細について発表させていただきました。
(このときは管理画面、バッチサーバーまで移行完了していました)

PHPのバージョンアップ自体は3月中に完了していましたが、その後関連ライブラリのバージョンアップも併せて行いました。

バージョンアップに向けたCI改善

2019/2/5にCakePHP1.3→2.8バージョンアップが完了し、その後すぐにCI周りの改善に取り掛かりました。

その詳細をPHP5.6化に向けたCircleCIのアップデートにまとめています。

目的は以下の2点です。

  • PHP5.6の文法に対応する
    • @PSR2を設定
    • @PHP56Migrationを設定
  • CIでUTを回す
    • UTが通らなければマージできないようにする

※PHP5.6との互換性を検証したく@PHP56Migrationを設定しましたが、これはあまり活躍しませんでした。
(PHP-CS-Fixerの@PHP56MigrationはPow関数の対応しかサポートされていないようです)
https://mlocati.github.io/php-cs-fixer-configurator/?version=2.2

PHP5.6バージョンアップ準備

PEARライブラリのコード管理

ランサーズは一部の機能にPEARライブラリを利用しています。
新規にサーバーをAnsibleで構築するにあたり、pear installでインストールしていました。

しかし、pear installでインストールすると/usr/share/srcに配置されるため、ライブラリ管理がOS側に依存していました。
2019/1にpear.php.netが数週間停止する事態が起きたこともあり、php.pear.netに依存しないサーバー構築手順に変更しました。

利用していたPEARライブラリは以下2つです。

  • Math Stats
    • Vendorディレクトリに直接配置
  • Crypt Browfish
    • Composerで管理

Crypt Browfishは依存関係があり、単純にVendorディレクトリに配置するだけでは動作しないため、
composer.jsonに以下のように記述して管理するようにしました。

  "repositories": [
    {
      "type": "vcs",
      "url": "git@github.com:pear/Crypt_Blowfish.git"
    }
  ],
  "require": {
    "pear/crypt_blowfish": "dev-master#8a56b74",
  }

※これらのライブラリはPHP7に対応していないので、代替手段を用意しておきたいところです。

AWS SDK PHPをV2に統一

AWS SDKについては、V2をメインに利用していましたが、S3関連の処理だけV1を利用していました。
AWS SDK V1はPHP5.6の環境ではStrict Warningを出してしまうため、すべてV2に統一しました。

PHP5.6コンテナの構築と切り替え

まず開発用コンテナのPHP5.6化から始めました。

ランサーズの開発環境はDockerを利用しており、docker-compose.ymlには以下のように記述しております。

version: '2'

services:
  app:
    image: xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/lancers_app:latest
    hostname: app
    networks:
      lancers:
        ipv4_address: 10.100.6.11
    extra_hosts:
       - "dev.lancers.jp:10.100.50.11"
…
    container_name: app-6-11
    volumes:
      - ~/www:/var/www

PHP5.3環境とPHP5.6環境をすぐに切り替えられるようにしました。
構築したPHP5.6のコンテナはタグ名を5.6とし、docker-compose.override.ymlを以下のように記述します。

version: '2'

services:
  app:
    image: xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/lancers_app:5.6

PHP5.6で稼働させたい場合は、このdocker-compose.override.ymlを配置して

$ docker-compose up -d

とすれば、PHP5.6コンテナにすぐに切り替わります。

PHP5.3コンテナに戻したい場合は、imageの行を#でコメントアウトし、再度

$ docker-compose up -d

とすれば戻ります。

PHP5.6対応

以前PHP5.6コンテナに切り替えて検証したときには、
CakePHP1.3とAWS PHP SDK V1のソースが大量のStrict Warningを出していました。

今回、CakePHP2.8とAWS PHP SDK V2にそれぞれバージョンアップして臨んだのですが、
まだStrict Warningを出している箇所が残っていました。

親クラスと子クラスの引数を合わせる

一番多かったのは、親クラスと子クラスの引数が一致していないパターンです。
PHP5.3では警告されませんでしたが、PHP5.6では以下の警告が出力されます。

Strict Standards: Declaration of WorkTask::afterSave() 
should be compatible with Model::afterSave($options = Array) 

例えば、この例では、WorkTask::afterSave関数の引数が以下のように定義されているのに対し、

public function afterSave($created)

親クラスのModel.phpでは、以下のように定義されていました。

public function afterSave($created, $options = array())

CakePHP1.3→2.8にバージョンアップした過程で引数の仕様変更があったためです。

以下のソースの子クラス全関数の引数をチェックし、親クラスと引数を一致させるように修正しました。

  • Model.php
    • Behavior.php
  • Controller.php
    • Component.php

参照を引数に取る関数の対応

PHP5.4からの仕様変更。
例えば、以下のコードで

$key = array_shift(array_keys($data));

以下の警告が出力されます

Strict (2048): Only variables should be passed by reference

参照を引数にとる関数は一度変数に格納する必要がありました。

$keys = array_keys($data);
$key = array_shift($keys);

参照が戻り値の関数の対応

PHP5.4からの仕様変更。
PHP5.3で戻り値を参照として受け取っていると

$Db =& ConnectionManager::getDataSource($model->useDbConfig);

以下の警告が出力されます

Strict (2048): Only variables should be assigned by reference

これは実体のまま受け取るように修正して対応しました。

$Db = ConnectionManager::getDataSource($model->useDbConfig);

初期化せずにオブジェクトとみなして代入

PHP5.6では以下のようにいきなり代入すると、

$record->type = 'type1’;

以下の警告が出力されます

Warning Error: Creating default object from empty value in ...

オブジェクトのメンバ変数を初期化する場合は、まずオブジェクト自体の初期化が必要です。
※入れ子の場合でも初期化が必要

$record = new stdclass();
$record->type = 'type1';

$record->fields = new stdclass();
$record->fields->key = 'key1';

PHP5.6化後のパフォーマンス

サーバーレスポンス

移行前に160ms前後であったものが140ms前後に改善。
アクセラレータがAPC → APCu + OPCacheになりましたが、その効果が出ていると推測しています。

バッチの実行時間

最も時間がかかっていた7時間のバッチが、30分ほど短縮されました。
全体的には、約1.13倍程度のパフォーマンスアップになりました。

関連ライブラリのバージョンアップ

PHP5.6化に伴い、composerで管理している各種ライブラリのバージョンアップも行いました。
詳細は別途ブログに書きたいと思います。

バージョンアップ資料の共有

PHP5.6バージョンアップ手順の詳細をGithubで公開しました。
https://github.com/LancersDevTeam/PHP_versionup

今更感はありますが、今後、移行する方の参考になりましたら幸いです。

今後の予定

ランサーズのPHP、CakePHPバージョンアップは、以下のフェーズに分けて取り組んでいます。

Apache + mod_php + PHP 5.3 + CakePHP 1.3
↓(第1フェーズ)
Nginx + PHP-FPM + PHP 5.3 + CakePHP 1.3
↓(第2フェーズ)
Nginx + PHP-FPM + PHP 5.3 + CakePHP 2.8
↓(第3フェーズ)
Nginx + PHP-FPM + PHP 5.6 + CakePHP 2.8
↓(第4フェーズ)
Nginx + PHP-FPM + PHP 5.6 + CakePHP 2.10
↓(第5フェーズ)
Nginx + PHP-FPM + PHP 7.x + CakePHP 2.10

今回、第3フェーズを終えることができました。

続きまして、第4フェーズである、CakePHP2.10化に着手いたします。
これが終われば、いよいよPHP7化に着手できます。

PHP5.6もすでにセキュリティサポートが切れていますのでできるだけ早くPHP7化に着手したいところです。

ランサーズではサービスを成長させてくれるエンジニア、デザイナーを募集しています!
ご興味がある方は、以下URLよりご応募ください。


【中途採用】
サービスリードエンジニア
テックリード(アーキテクト)
フロントエンドエンジニア
サーバーサイドエンジニア
業務エンジニア(社内システム基盤・基幹システム)

【インターン・学生バイト】
19新卒対象サマーインターン
エンジニアインターン

その他採用情報

関連記事

2017年は合計58回の技術イベントと勉強会をランサーズ会場で開催しました

ランサーズ Advent Calendar 2017 の 24日目を担当してる nakajiman です。 ランサーズのエンジニアチームは、技術イベントや勉強会への参加、登壇、スポンサードの取り組みはもちろんのこと、それらに加えて、ランサーズ会場への技術イベン …

thumbnail
プログラミング言語Go読書会 (まえがき- 1.2)

どうも、ameshoです。 先日Lancersで開催された「Go 読書会 #1」の記録をQiitaに書きました。 http://qiita.com/amesho/items/0d2ea220a1ee11019759 よろしくお願いします。

PHP, CakePHPバージョンアップに向けてCIで品質を担保・向上していく

こんにちは、エンジニアの上野です。 今回はソース例や実際のサンプルソースを交えながら 「PHPバージョンアップに向けてCIで品質を担保・向上していく」と題してlancers.jp本体に導入しているCircleCIでの取り組みについてご紹介します。 導入背景 P …