既存アプリをPHP7へ移行する前にするべき6つのこと
PHP 7.0.0-RC6 がリリースされ、PHP7の正式リリースが迫っています(予定では2015/11/12)。今日は、既存アプリのPHP7への移行について整理しておきます。
(2015-12-04 追記) 12/3(日本時間では12/4の早朝)にPHP 7.0.0が 正式にリリース されました。
既存アプリをPHP7に移行する前には以下を実施するとよいです。
- テスト環境を構築する
- 拡張モジュールの対応状況を調べる
- ライブラリなどの対応状況を調べる
- 変更点に関するドキュメントを読む
- php7ccをかける
- コードを修正しテストする
6つあげてますが、結局はPHP7で「テストする」ということに尽きます。
テスト環境を構築する
PHP7の実行環境がなければ始まりません。Vagrantなどでテスト環境を構築できます。探せば色々あると思いますが、1つだけ紹介するとすれば、Rasmusさんのphp7devでしょうか。
参考:PHP7のテスト環境を構築するための少しだけ長い道のり
(2015-11-30 追記) 「PHP7の開発環境をVagrant+CentOS7上に30分で構築する」を書きました。
また、CentOS環境がすでにある場合は、RemiのRPMがすでにありますので、それを使うのが簡単でしょう。
テスト環境が用意できたら、PHPのバージョンを確認しましょう。
vagrant@php7dev:~/php-src$ php -v
PHP 7.0.1-dev (cli) (built: Oct 29 2015 10:14:58) ( NTS )
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0-dev, Copyright (c) 1998-2015 Zend Technologies
with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies
なお、本番環境の移行の前には、本番環境と同じ環境のステージング環境でテストしてください。
拡張モジュールの対応状況を調べる
PHP5用の拡張モジュール(エクステンション)はPHP7では動作しません。
PHP本体に含まれない拡張モジュールを使っている場合は、対応状況を確認する必要があります。
対応状況をまとめているプロジェクトが以下にあります。
この拡張モジュールがPHP7対応しているかどうかが最大の問題かも知れません。
ここに引っかかる例として、Phalconなどの拡張モジュールのフレームワークがあります。
Phalconについては、2.x系はZephirという拡張モジュールのコードを生成する言語で作成されており、ZephirがPHP7対応する必要があります。
ZephirのPHP7対応は初期段階であり、まだ完成はしていません。
ライブラリなどの対応状況を調べる
(PHPで書かれた)ライブラリやフレームワークがPHP7に対応していなければ、
- (あれば)対応したバージョンにアップグレードする
- 自分で対応させる
- 別の対応したライブラリに入れ替える
のいずれかを選択する必要があります。
フレームワークの対応状況はいまいちわかりづらいものもありますが。
フレームワーク | バージョン | 状況 |
---|---|---|
BEAR.Sunday | 1.0 | 対応済み |
CakePHP | 3.1.5 | 対応(CakePHP 3.1.5 Released) |
2.7以降 | 対応?ただし、String クラスを使っている場合はCakeText クラスに置換が必要 |
|
CodeIgniter | 3.0 | 対応 |
FuelPHP | 1.8-dev(1.7.4以降) | 対応。ただし、Error クラスをカスタマイズしている場合はErrorhandler クラスに変更が必要 |
Symfony | メンテされているバージョン | 対応済み(Symfony achieves 100% PHP7 compatibility) |
Yii | 2.0 | 対応(PHP 7 released) |
1.1.17以降 | 対応(PHP 7 released) |
なお、PEARについては、1.10.0で対応しています。
ライブラリやフレームワークが対応しているからといって安心してはいけません。問題はアプリが対応しているかどうかです。
変更点に関するドキュメントを読む
まず読むべきはPHPマニュアルです。全部読みましょう。
既存アプリで結構引っかかりそうなのがクラス名の衝突です。名前空間を使ってないと衝突の可能性があり、衝突したらアプリを修正するしかありません。以下が使えないクラス名の一覧です。
使えなくなったクラス名
- bool
- int
- float
- string
- NULL
- TRUE
- FALSE
将来使えなくなるクラス名
- resource
- object
- mixed
- numeric
新しいクラス名(つまりユーザ定義できない)
- IntlChar
- ReflectionGenerator
- ReflectionType
- SessionUpdateTimestampHandlerInterface
- Throwable
- Error
- TypeError
- ParseError
- AssertionError
- ArithmeticError
- DivisionByZeroError
次に読むべきは、PHP 7.0 UPGRADE NOTESです。PHPマニュアルよりも細かいことが記載されています。必要に応じて読みましょう。
php7ccをかける
次にPHP 7 Compatibility Checkerをかけます。
(2015-12-04 追記) php7cc以外にも「PHP 7 Migration Assistant Report (MAR)」というのもありました。
ここでは、php7ccをComposerからインストールします。
$ composer global require sstalle/php7cc
以下のように実行します。--extensions
オプションで拡張子を指定できます。
$ php7cc --extensions=php,ini fuel/core/
除外したいフォルダがある場合は、--except
オプションで指定します。
$ php7cc --except=vendor --except=core/tests fuel/
上記では、fuel/vendor
とfuel/core/tests
フォルダが除外されます。
例えば、以下のようなレポートが出力されます。
File: /home/vagrant/fuel-1.8-dev/fuel/core/vendor/phpseclib/Net/SSH2.php
> Line 1734: Function argument(s) returned by "func_get_args" might have been modified
func_get_args();
...
File: /home/vagrant/fuel-1.8-dev/fuel/core/classes/database/mysql/result.php
> Line 23: Removed function "mysql_num_rows" called
mysql_num_rows($result);
> Line 30: Removed function "mysql_free_result" called
mysql_free_result($this->_result);
> Line 36: Removed function "mysql_data_seek" called
mysql_data_seek($this->_result, $offset);
> Line 62: Removed function "mysql_fetch_object" called
mysql_fetch_object($this->_result);
> Line 67: Removed function "mysql_fetch_object" called
mysql_fetch_object($this->_result, $this->_as_object);
> Line 72: Removed function "mysql_fetch_assoc" called
mysql_fetch_assoc($this->_result);
...
File: /home/vagrant/fuel-1.8-dev/fuel/core/classes/database/query/builder/insert.php
> Line 96: Function argument(s) returned by "func_get_args" might have been modified
func_get_args();
...
File: /home/vagrant/fuel-1.8-dev/fuel/core/classes/session.php
> Line 72: Check that callbacks that are passed to "session_set_save_handler" and return false or -1 (if any) operate correctly
session_set_save_handler(function ($savePath, $sessionName) {
}, function () {
}, function ($sessionId) {
$_SESSION = \Session::get();
$_SESSION['__org'] = $_SESSION;
}, function ($sessionId, $data) {
$org = isset($_SESSION['__org']) ? $_SESSION['__org'] : array();
unset($_SESSION['__org']);
if ($remove = array_diff_key($org, $_SESSION)) {
\Session::delete(array_keys($remove));
}
empty($_SESSION) or \Session::set($_SESSION);
}, function ($sessionId) {
\Session::destroy();
}, function ($lifetime) {
});
File: /home/vagrant/fuel-1.8-dev/fuel/packages/orm/classes/model/nestedset.php
> Line 812: Possible array element creation during by-reference assignment
$tracker[$index] =& $tree[$this->{$pk}];
> Line 867: Possible array element creation during by-reference assignment
$tracker[$index + 1] =& $tracker[$index]->_custom_data[$children][$treenode->{$pk}];
> Line 871: Possible array element creation during by-reference assignment
$tracker[$index + 1] =& $tracker[$index][$children][$treenode->{$pk}];
Checked 375 files in 26.485 seconds
コードを修正しテストする
php7ccで報告された点を確認しつつ、必要ならコードを修正し、テストしてください。
vagrant@php7dev:~/fuel-1.8-dev$ php oil test
Tests Running...This may take a few moments.
PHPUnit 5.0.8 by Sebastian Bergmann and contributors.
............................................................... 63 / 389 ( 16%)
............................................................... 126 / 389 ( 32%)
............................................................... 189 / 389 ( 48%)
............................................................... 252 / 389 ( 64%)
............................................................... 315 / 389 ( 80%)
............................................................... 378 / 389 ( 97%)
........... 389 / 389 (100%)
Time: 653 ms, Memory: 14.00Mb
OK (389 tests, 483 assertions)
ドキュメントされていないバグと思われる動作がもしあれば、https://bugs.php.net/ を調べて、報告がなければとりあえずバグ報告しましょう。
Rasmusさんの教え
PHPカンファレンスでRasmusさんは、自分は本番環境にPHP 7.0.0は使わないと言っていました。しかし、7.1まで待つ必要はないとも。
参考
Date: 2015/10/30