下位互換性のない変更点

エラーや例外の取り扱いの変更

fatal error や recoverable fatal error の多くが、PHP 7 では例外に変換されるようになりました。 これらの例外は Error クラスを継承したもので、 このクラスは Throwable インターフェイスを実装しています。 この新しいインターフェイスを、すべての例外が実装しています。

エラーではなく例外がスローされるようになるということは、自作のエラーハンドラは呼び出されなくなるということです (Error 例外をキャッチしなかった場合は、fatal エラーが発生します)。

PHP 7 におけるエラーハンドリングの詳細な説明は PHP 7 のエラー を参照ください。 この移行ガイドでは、下位互換性のない変更点を列挙するだけにとどめます。

set_exception_handler() が常に Exception オブジェクトを受け取るとは限らない

set_exception_handler() で登録した例外ハンドラの実装で Exception 型を宣言している場合は、 Error オブジェクトがスローされると fatal エラーが発生します。

PHP 5 と PHP 7 の両方で動くハンドラを書く場合は、ハンドラで型宣言をしてはいけません。 PHP 5 で動いていたコードを移行する際に、そのコードが PHP 7 でだけ動けばいいのなら、 Exception 型で宣言している部分を単純に Throwable 型に置換するだけでかまいません。

<?php
// PHP 5 でのこの実装は、そのままでは PHP 7 では動きません
function handler(Exception $e) { ... }
set_exception_handler('handler');

// PHP 5 と 7 の両方で動きます
function handler($e) { ... }

// PHP 7 でだけ動きます
function handler(Throwable $e) { ... }
?>

内部のコンストラクタは、失敗したときに常に例外をスローする

これまでは、コンストラクタの処理が失敗した際に、 NULL を返したり使用不能なオブジェクトを返したりする内部クラスがありました。 PHP 7 では、同様の場合に Exception をスローするようになりました。 ユーザー定義のクラスでは以前からそうすべきだとされていたことです。

パースエラーが発生すると ParseError をスローする

パースエラーが発生すると ParseError オブジェクトをスローするようになりました。 eval() のエラーハンドリングをする際には、catch ブロックを用意してこのエラーを処理しなければいけません。

E_STRICT 通知の深刻度の変更

すべての E_STRICT 通知が、改めて別のレベルに移動しました。 定数 E_STRICT はそのまま残っているので、 error_reporting(E_ALL|E_STRICT) のような呼び出しがエラーになることはありません。

E_STRICT 通知の深刻度の変更
状況 新しいレベル / 挙動
Indexing by a resource E_NOTICE
Abstract static methods 通知は削除され、エラーにはならない
"Redefining" a constructor 通知は削除され、エラーにはならない
Signature mismatch during inheritance E_WARNING
Same (compatible) property in two used traits 通知は削除され、エラーにはならない
Accessing static property non-statically E_NOTICE
Only variables should be assigned by reference E_NOTICE
Only variables should be passed by reference E_NOTICE
Calling non-static methods statically E_DEPRECATED

変数の取り扱いの変更

PHP 7 では、抽象構文木を使ってソースファイルをパースするようになりました。 そのおかげで言語としてのさまざまな改良ができるようになりました。 これまでの PHP が使っていたパーサーでは不可能だったこともできるようになったからです。 しかしその結果、一貫性を保つために一部の機能を削除することになりました。 これは、下位互換性を損ねるものです。 このセクションでは、それらについて説明します。

変数やプロパティ、メソッドへの間接的なアクセスの扱いの変更

変数やプロパティそしてメソッドへの間接的なアクセスを、厳密に左から右の順で評価するようになりました。 以前のバージョンでは、場合によって評価の順が逆転することもありました。 評価順の変更を、以下の表にまとめます。

間接的なアクセスの評価順の変更
PHP 5 での解釈 PHP 7 での解釈
$$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz']
$foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz']
$foo->$bar['baz']() $foo->{$bar['baz']}() ($foo->$bar)['baz']()
Foo::$bar['baz']() Foo::{$bar['baz']}() (Foo::$bar)['baz']()

今までのバージョンにおける右から左の評価を想定しているコードは、 波括弧を使って評価順を明示するように (表の中央列のように) 書き直す必要があります。 そうすれば、PHP 7.x との互換性を保ちつつ、PHP 5.x との下位互換性も維持できます。

これは、global キーワードにも影響します。 必要であれば、波括弧構文を使えばこれまでのバージョンでの挙動を再現できます。

<?php
function f() {
    
// PHP 5 でしか使えません
    
global $$foo->bar;

    
// PHP 5 と PHP 7 の両方で使えます
    
global ${$foo->bar};
}
?>

list() の取り扱いの変更

list() での変数の代入が、逆順ではなくなる

list() における変数への代入が定義された順番どおりに行われるようになりました。 今までのように逆順にはなりません。 この変更の影響を受けるのは、list()[] 演算子と組み合わせて使うときくらいでしょう。その例を示します。

<?php
list($a[], $a[], $a[]) = [123];
var_dump($a);
?>

上の例の PHP 5 での出力は、このようになります。

array(3) {
  [0]=>
  int(3)
  [1]=>
  int(2)
  [2]=>
  int(1)
}

上の例の PHP 7 での出力は、このようになります。

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

一般論として、 list() での代入がどの順で行われるかに依存するコードは書かないことを推奨します。 代入の順番は、実装の都合によって今後も変わる可能性があるからです。

空の list() の廃止

空の list() を作ることはできなくなりました。 次のようなコードは PHP 7 では使えません。

<?php
list() = $a;
list(,,) = 
$a;
list(
$x, list(), $y) = $a;
?>
list() は文字列を展開しない

list() は文字列変数を展開できなくなりました。 かわりに str_split() を使いましょう。

参照による代入で自動的に作成した配列要素の並び順の変更

参照による代入で配列の要素を自動的に作成した場合の、 要素の並び順が変更されました。 以下に例を示します。

<?php
$array 
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>

上の例の PHP 5 での出力は、このようになります。

array(2) {
  ["b"]=>
  &int(1)
  ["a"]=>
  &int(1)
}

上の例の PHP 7 での出力は、このようになります。

array(2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}

関数のパラメータを括弧で囲んでもその振る舞いは変わらない

PHP 5 では、関数のパラメータを冗長な括弧で囲んでおくと、 関数のパラメータを参照渡しにした場合の警告を抑止することができました。 PHP 7 では、たとえ括弧で囲んでも警告が常に発生します。

<?php
function getArray() {
    return [
123];
}

function 
squareArray(array &$a) {
    foreach (
$a as &$v) {
        
$v **= 2;
    }
}

// PHP 7 では警告が発生します
squareArray((getArray()));
?>

上の例の出力は以下となります。

Notice: Only variables should be passed by reference in /tmp/test.php on line 13

foreach の変更

foreach の振る舞いが多少変わりました。 主に、内部の配列ポインタの扱いや、反復処理中の配列の変更に関する部分です。

foreach は内部の配列ポインタを変更しない

PHP 7 より前のバージョンでは、foreach で配列を反復処理する際に、内部の配列ポインタを変更していました。 PHP 7 ではそのようにはならず、以下の例のようになります。

<?php
$array 
= [012];
foreach (
$array as &$val) {
    
var_dump(current($array));
}
?>

上の例の PHP 5 での出力は、このようになります。

int(1)
int(2)
bool(false)

上の例の PHP 7 での出力は、このようになります。

int(0)
int(0)
int(0)

値渡しの foreach は、配列のコピーを使って操作を進める

デフォルトの値渡しモードの場合の foreach は、 配列そのものではなくそのコピーを使って反復処理を進めるようになりました。 つまり、処理中に配列を書き換えた場合でも、反復処理の対象となる値には影響が及びません。

参照渡しの foreach の、反復処理の振る舞いを改良

参照渡しでの foreach における、 処理中の配列への変更の追跡が改良されました。 たとえば、処理中の配列に新たな要素を追加した場合に、 追加した新たな要素も反復処理の対象に含まれるようになります。

<?php
$array 
= [0];
foreach (
$array as &$val) {
    
var_dump($val);
    
$array[1] = 1;
}
?>

上の例の PHP 5 での出力は、このようになります。

int(0)

上の例の PHP 7 での出力は、このようになります。

int(0)
int(1)

Traversable でないオブジェクトの反復処理

Traversable ではないオブジェクトの反復処理の挙動が、 配列を参照渡しで反復処理したときと同じようになりました。 反復処理中の配列を変更したときの挙動の改良 も適用され、処理中のオブジェクトにプロパティを追加したり削除したりした場合に、 それが反復処理に反映されます。

integer の取り扱いの変更

無効な形式の八進リテラル

以前のバージョンでは、無効な数値が八進リテラルに含まれている場合は、 単純にそれを無視していました (たとえば 0128012 として扱っていました)。 PHP 7 では、このような場合にパースエラーが発生します。

負のビットシフト

ビットシフトに負の数を指定すると、 ArithmeticError をスローするようになりました。

<?php
var_dump
(>> -1);
?>

上の例の PHP 5 での出力は、このようになります。

int(0)

上の例の PHP 7 での出力は、このようになります。

Fatal error: Uncaught ArithmeticError: Bit shift by negative number in /tmp/test.php:2
Stack trace:
#0 {main}
  thrown in /tmp/test.php on line 2

範囲外のビットシフト

integer のビット幅を超えるビットシフト (左右問わず) を行うと、結果は常に 0 となります。 以前のバージョンでは、このときの振る舞いはアーキテクチャに依存していました。

ゼロ除算の挙動の変更

以前のバージョンでは、除算演算子 (/) や剰余演算子 (%) の除数に 0 を使うと、E_WARNING が発生して結果は false となっていました。 PHP 7 では、除算演算子の返す結果は float で、 +INF、-INF あるいは NAN のいずれかとなります。 これは、IEEE 754 で指定された挙動です。 剰余演算子については E_WARNING が発生しなくなり、 DivisionByZeroError 例外をスローするようになりました。

<?php
var_dump
(3/0);
var_dump(0/0);
var_dump(0%0);
?>

上の例の PHP 5 での出力は、このようになります。

Warning: Division by zero in %s on line %d
bool(false)

Warning: Division by zero in %s on line %d
bool(false)

Warning: Division by zero in %s on line %d
bool(false)

上の例の PHP 7 での出力は、このようになります。

Warning: Division by zero in %s on line %d
float(INF)

Warning: Division by zero in %s on line %d
float(NAN)

PHP Fatal error:  Uncaught DivisionByZeroError: Modulo by zero in %s line %d

文字列の取り扱いの変更

十六進数値形式の文字列は数値とはみなさない

十六進形式の数値を含む文字列は数値とはみなされなくなりました。 以下に例を示します。

<?php
var_dump
("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" "0x1");
var_dump(substr("foo""0x1"));
?>

上の例の PHP 5 での出力は、このようになります。

bool(true)
bool(true)
int(15)
string(2) "oo"

上の例の PHP 7 での出力は、このようになります。

bool(false)
bool(false)
int(0)

Notice: A non well formed numeric value encountered in /tmp/test.php on line 5
string(3) "foo"

filter_var() を使えば、 文字列が十六進数値形式であるかどうかをチェックでき、 その文字列を integer に変換することもできます。

<?php
$str 
"0xffff";
$int filter_var($strFILTER_VALIDATE_INTFILTER_FLAG_ALLOW_HEX);
if (
false === $int) {
    throw new 
Exception("Invalid integer!");
}
var_dump($int); // int(65535)
?>

\u{ がエラーの原因になることがある

Unicode コードポイントのエスケープ構文 が導入されたことにより、\u{ のあとに無効なシーケンスが続く文字列が fatal error となる可能性があります。 これを回避するには、先頭のバックスラッシュをエスケープする必要があります。

削除された関数

call_user_method() および call_user_method_array()

これらの関数は PHP 4.1.0 で非推奨となり、 call_user_func() および call_user_func_array() を使うことが推奨されていました。 あるいは 可変関数... 演算子を使うことを検討しましょう。

ereg* 系のすべての関数

ereg 関数はすべて削除されました。かわりに PCRE を使うことを推奨します。

mcrypt のエイリアス

非推奨の mcrypt_generic_end() 関数が削除されました。 かわりに mcrypt_generic_deinit() を使いましょう。

さらに、非推奨の mcrypt_ecb()mcrypt_cbc()mcrypt_cfb()mcrypt_ofb() も削除されました。 mcrypt_decrypt() に、適切な MCRYPT_MODE_* 定数を組み合わせて使いましょう。

すべての ext/mysql 関数

ext/mysql のすべての関数が削除されました。 その他の MySQL API の選択肢については MySQL API の選択 を参照ください。

すべての ext/mssql 関数

ext/mssql のすべての関数が削除されました。 代替となる選択肢については、 MSSQL の導入ページ を参照ください。

intl のエイリアス

非推奨のエイリアス datefmt_set_timezone_id() および IntlDateFormatter::setTimeZoneID() が削除されました。 かわりに datefmt_set_timezone() および IntlDateFormatter::setTimeZone() を使いましょう。

set_magic_quotes_runtime()

set_magic_quotes_runtime() およびそのエイリアスである magic_quotes_runtime() が削除されました。 これらは PHP 5.3.0 で非推奨となり、 PHP 5.4.0 でマジッククォートが廃止された時点で事実上無意味になっていました。

set_socket_blocking()

非推奨のエイリアス set_socket_blocking() が削除されました。 かわりに stream_set_blocking() を使いましょう。

PHP-FPM における dl()

dl() が PHP-FPM で使えなくなりました。 CLI や embed SAPI では今でも使えます。

GD Type1 関数群

GD 拡張モジュールから、PostScript Type1 フォントのサポートが削除されました。 その結果として、以下の関数群が削除されました。

かわりに、TrueType フォントやそれに関連する関数群を使いましょう。

削除された INI 項目

削除された機能

以下の INI 項目は、関連する機能の削除に伴って削除されました。

xsl.security_prefs

xsl.security_prefs が削除されました。 かわりに XsltProcessor::setSecurityPrefs() メソッドを用いて、プロセッサ単位のセキュリティ設定を制御しましょう。

下位互換性のないその他の変更

新しいオブジェクトを参照渡しで代入できない

new 文の結果を参照渡しで変数に代入することができなくなりました。 by reference:

<?php
class {}
$c =& new C;
?>

上の例の PHP 5 での出力は、このようになります。

Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3

上の例の PHP 7 での出力は、このようになります。

Parse error: syntax error, unexpected 'new' (T_NEW) in /tmp/test.php on line 3

無効なクラス名、インターフェイス名、トレイト名

以下の名前は、クラスやインターフェイスそしてトレイトの名前としては使えなくなりました。

さらに、以下に挙げる名前も使うべきではありません。 PHP 7.0 の時点ではまだエラーにはなりませんが、 これらの名前は将来のバージョン用に予約されており、いずれ使えなくなると考えるべきです。

ASP タグと script タグの廃止

ASP 形式のタグや script タグを使って PHP コードを囲むことはできなくなりました。 この影響を受けるのは、以下のタグです。

削除された ASP タグおよび script タグ
開始タグ 終了タグ
<% %>
<%= %>
<script language="php"> </script>

非互換のコンテキストからの呼び出しの削除

既に PHP 5.6 で非推奨になっていますが、 static ではないメソッドに対して非互換のコンテキストで static 呼び出しを行うと、 呼ばれた側のメソッドが未定義の $this 変数を持つことになって警告が発生します。

<?php
class {
    public function 
test() { var_dump($this); }
}

// クラスAを継承して「いない」ことに注目
class {
    public function 
callNonStaticMethodOfA() { A::test(); }
}

(new 
B)->callNonStaticMethodOfA();
?>

上の例の PHP 5.6 での出力は、このようになります。

Deprecated: Non-static method A::test() should not be called statically, assuming $this from incompatible context in /tmp/test.php on line 8
object(B)#1 (0) {
}

上の例の PHP 7 での出力は、このようになります。

Deprecated: Non-static method A::test() should not be called statically in /tmp/test.php on line 8

Notice: Undefined variable: this in /tmp/test.php on line 3
NULL

yield が右代入演算子に

yield で括弧が必須ではなくなり、右代入演算子に変わりました。 優先順位は print=> の間になります。 これによって、以下のように振る舞いが変わります。

<?php
echo yield -1;
// 以前はこのように解釈されました
echo (yield) - 1;
// PHP 7 ではこのように解釈されます
echo yield (-1);

yield $foo or die;
// 以前はこのように解釈されました
yield ($foo or die);
// PHP 7 ではこのように解釈されます
(yield $foo) or die;
?>

括弧を使えば、曖昧さを排除できます。

同じ名前のパラメータをひとつの関数に複数定義できない

関数内の複数のパラメータを同じ名前にすることができなくなりました。 たとえば次のようなメソッドは E_COMPILE_ERROR となります。

<?php
function foo($a$b$unused$unused) {
    
//
}
?>

引数を調べる関数は、パラメータの その時点での 値を報告する

func_get_arg(), func_get_args(), debug_backtrace() といった関数や例外時のバックトレースで得られる値が、 パラメータとして渡されたときの値ではなくなりました。 その時点での値が得られるようになります (つまり、パラメータとして渡された値から変更されている可能性があります)。

<?php
function foo($x) {
    
$x++;
    
var_dump(func_get_arg(0));
}
foo(1);?>

上の例の PHP 5 での出力は、このようになります。

1

上の例の PHP 7 での出力は、このようになります。

2

Switch 文に複数の default ブロックを書けない

ひとつの switch 文の中に、複数の default ブロックを定義することができなくなりました。 たとえば次の switch 文は E_COMPILE_ERROR になります。

<?php
switch (1) {
    default:
    break;
    default:
    break;
}
?>

$HTTP_RAW_POST_DATA の削除

$HTTP_RAW_POST_DATA が使えなくなりました。かわりに php://input ストリームを使いましょう。

INI ファイルにおける # 形式のコメントの削除

INI ファイルにおいて # で始まる行をコメントとする機能が削除されました。 かわりに ; を使いましょう。 この変更は、php.ini だけではなく、 parse_ini_file()parse_ini_string() が扱うファイルにもあてはまります。

JSON 拡張モジュールが JSOND に置き換わる

JSON 拡張モジュールが JSOND に置き換わりました。 下位互換性を損ねるちょっとした変更が二点あります。 まず、数値の最後を小数点で終えることができなくなりました (つまり、 34. とすることはできず、34.0 あるいは 34 としなければいけません)。 次に、科学記法を使う際に、指数記号 e を小数点の直後に置くことができなくなりました (つまり、3.e3 とすることはできず、 3.0e3 あるいは 3e3 としなければいけません)。 最後に、空の文字列は妥当な JSON だとみなされなくなりました。

内部関数がオーバーフローしたときの挙動

これまでのバージョンでは、浮動小数点数値が大きすぎて整数として表せない場合に、 float から integer に変換した結果を黙って切り詰めていました。 PHP 7 では E_WARNING が発生し、NULL を返します。

カスタムセッションハンドラの戻り値の修正

カスタムセッションハンドラとして実装した関数が FALSE あるいは -1 を返すとき、fatal error が発生します。 この関数が boolean 値か -1, あるいは 0 以外を返す場合は、その関数は失敗して E_WARNING が発生します。

同値な要素の並び順

内部的なソートアルゴリズムが改良されたことに伴って、 比較したときに等しいとみなされる要素の並び順が以前とは変わるかもしれません。

注意:

同値な要素の並び順に依存するコードは書かないようにしましょう。 その並び順がいつまでも同じであるとは限りません。

break 文と switch 文の位置の間違い

ループまたは switch 制御構造の外の break および continue 文は、 以前のように実行時ではなくコンパイル時に検出され、 E_COMPILE_ERROR を起こします。

Mhash はもう拡張機能ではありません

Mhash 拡張は Hash 拡張に完全に統合されました。 したがって、extension_loaded() で Mhash サポートを検出できなくなりました。 代わりに function_exists() を使用してください。 さらに、Mhash は get_loaded_extensions() および関連機能により報告されなくなりました。

declare(ticks)

declare(ticks) ディレクティブは、異なるコンパイル単位にリークしなくなりました。