互換性がなくなるコード
PHP 7になると、PHP 5.xまでと違って明らかに問題となるコードもあり、ある程度影響が大きいと思われる変更点を紹介します。また、ここで紹介するもの以外にもありますので、下記のドキュメントを参照してください。
基本型と同名のクラス宣言
PHP 7では、新機能として関数や関数の引数に型宣言として基本型が使えるようになったり、新しい最上位のエラークラスとしてErrorクラスが追加されたりしました。PHP 7でこれらの基本型とクラス名がかぶる場合には問題となります。したがって、リスト3のようなstringクラスは作成ができなくなりました。ただし、厳密にはまだ、resource、object、mixed、numericなどは使えるようですが、これらも同様に使うべきクラス名ではないため、その利用は控える必要があります。
class String{ } $str = new String();
あまり、stringといったクラスを定義するようなケースは実際の利用ではないとは思いますが、フレームワークなどではタイプヒンティングなどを基本型相当にも適用するなどの拡張を行うケースが考えられます。実際にCakePHP2.6まではstringクラスが存在(2.7でこれに対応)していたようです。
オブジェクトの作成時(new)での参照渡し
オブジェクトを作成する際にnewで作成した値をそのまま参照渡しで変数に設定することは、PHP 4ではよくあるケースでした。PHP 5.xでは既に推奨されないコードでしたが、PHP 7ではエラーになるようになりましたので、リスト4のようなコードは記述できなくなります。
class Foo{} $foo =& new Foo();
変数の取り扱いの変更
可変変数での配列やプロパティにアクセスする場合の評価する順番が、PHP 5.xとPHP 7で変わました。
単純な変数表記であれば、PHP 5.xとPHP 7で問題となることはありませんが、配列を使った配列の参照やオブジェクト、メソッド参照を行っている場合に特に注意が必要になります。
式 | PHP 5での解釈 | PHP 7での解釈 |
---|---|---|
$$name['key']['value'] | ${$name['key']['value']} | ($$name)['key']['value'] |
$name->$key['value'] | $name->{$key['value']} | ($name->$key)['value'] |
$name->$key['value']() | $name->{$key['value']}() | ($name->$key)['value']() |
Person::$key['value']() | Person::{$key['value']}() | (Person::$name)['value']() |
これらで実際に問題となるコードがリスト5のようになります。
class Person{ function hello(){ echo "Hello\n"; } } $name = array( 'key' => array('value' => 'kobayashi' , 'method' => 'hello') ); $kobayashi = new Person(); var_dump($$name['key']['value']); //(1) var_dump(${$name['key']['value']}); //(2) $kobayashi->$name['key']['method'](); //(3) $kobayashi->{$name['key']['method']}(); //(4)
(1)では、実際には$kobayashiという変数を想定したコードですが、$$nameが先に解釈されるためにPHP 7では結果としてエラーとなります。したがって、(2)のようにしなければPHP 5でもPHP 7でも同じような動作にはなりません。
また、(3)は$kobayashi->hello()というコードを想定したものですが、PHP 7では$kobayashi->$nameが先に解釈されるためにエラーとなります。こちらも、同じようにPHP 7でも動作するようにするためには(4)のようにする必要があります。
また、関数内などでスコープ外の変数を扱うglobalでは、{}を使用しない可変変数自体の利用が禁止されました。
もともと、global自体推奨される機能ではありませんが、上記のような評価順が変わることにより、結果的にglobalで不明瞭な変数を指す可能性があることから、明示的な利用しか許可しないことはやむを得ないとも思います。
このように、PHP 7ではこのような変数を用いた変数の参照では、{}を使って明示的な評価順を記述するようにしましょう。
参照渡し時のforeachでの処理の違い
foreach内で大きなオブジェクトを扱う場合などでよく参照渡しによる処理をするケースがありますが、参照渡しでのforeachでは振る舞いが変わっていますので注意が必要になります。この振る舞いの違いによって結果の違いが発生するようなコードがリスト6のようになります。
$prefs = ["hokkaido","tokyo"]; //(1)foreach内でのcurrentの扱い方 foreach($prefs as &$name){ echo $name." --> next: "; echo current($prefs) ."\n"; } //(2)foreach内でのリストの変更 foreach($prefs as &$name){ if($name == 'tokyo'){ $prefs[] = "shibuya"; $prefs[] = "shinjyuku"; } var_dump($name); }
リスト6をPHP 5.xとPHP 7で実行した結果ではリスト7のように違いが生じます。
// PHP 5.xの実行結果 hokkaido --> next: tokyo tokyo --> next: string(8) "hokkaido" string(5) "tokyo" // PHP 7の実行結果 hokkaido --> next: hokkaido tokyo --> next: hokkaido string(8) "hokkaido" string(5) "tokyo" string(7) "shibuya" string(9) "shinjyuku"
foreach内のでcurrent()関数の扱いが代わり、PHP 5.xではforeach内で配列ポインタを移動していたので、current()関数で次の値を取得できましたが、PHP 7では配列ポインタを移動しないために、foreach内でcurrent()関数を使っても常に配列の最初の要素を示すようになります。
また、PHP 5.xではforeach内でリスト自体に要素を追加しても、foreachで繰り返されるのはforeach処理がされる前のリストでしたが、PHP 7ではforeach内でリストを追加するとその要素も繰り返し処理がされることになりました。
繰り返し処理内でそのリスト自身に変更を加えることはよくあるケースと思われるために、参照渡しでforeachを利用している場合には注意が必要です。ただし、参照渡しではない場合には、このようなforeach内でのリスト変更においてもPHP 5と同様の結果になります。