PHPのお勉強!

PHP TOP

下位互換性のない変更点

PHP コア

文字列と数値の比較

(厳密でないやり方で)数値と非数値文字列を比較する場合、 数値を文字列にキャストし、文字列と比較するようになりました。 数値と数値形式の文字列の比較は、以前と同じ振る舞いをします。 注意すべきなのは、これによって、 0 == "not-a-number"false と見なされるようになったことです。

比較 変更前 変更後
0 == "0" true true
0 == "0.0" true true
0 == "foo" true false
0 == "" true false
42 == " 42" true true
42 == "42foo" true false

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

  • match が予約語になりました。

  • mixed が予約語になりました。 よって、クラスやインターフェイス、 トレイトの名前として使えなくなっています。 名前空間の中であっても同様です。

  • アサーションに失敗すると、デフォルトで例外をスローするようになりました。 古い振る舞いを望む場合、php.ini で assert.exception=0 と設定できます。

  • クラス名と同じ名前のメソッドは、コンストラクタと解釈されなくなりました。 __construct() メソッドを代わりに使って下さい。

  • static でないメソッドを、staticメソッドとしてコールできる機能が削除されました。 static でないメソッドをクラス名を使ってチェックした場合、 is_callable() は失敗します。 (オブジェクトのインスタンスを使ってチェックしなければいけません)

  • (real)(unset) キャストが削除されました。

  • track_errors ini ディレクティブは削除されました。 つまり、php_errormsg が利用できなくなったということです。 代わりに error_get_last() 関数が使えます。

  • 大文字小文字を区別しない定数を定義できる機能が削除されました。 define() 関数の第3引数はもはや true ではありません。

  • __autoload() 関数を使ってオートローダーを指定する機能は削除されました。 代わりに spl_autoload_register() を使うべきです。

  • set_error_handler() 関数で設定されるカスタムエラーハンドラには、 errcontext 引数は渡されなくなりました。

  • create_function() 関数は削除されました。 無名関数が代わりに使えます。

  • each() 関数は削除されました。 代わりに foreachArrayIterator を使うべきです。

  • Closure::fromCallable()ReflectionMethod::getClosure() を使って メソッドから生成されたクロージャーから this の束縛を解除できる機能は削除されました。

  • this を使っている適切なクロージャーから、 this の束縛を解除する機能も削除されています。

  • オブジェクトに対して array_key_exists() 関数を使える機能は削除されました。 isset() または property_exists() を代わりに使えます。

  • array_key_exists() 関数の引数 key の型に関する振る舞いが、 isset() 関数や配列アクセスの場合と一貫したものになりました。 全てのキーの型は通常の強制が行われ、配列やオブジェクトのキーは TypeError がスローされるようになりました。

  • はじめの数値のキーとして n を持つ配列は、 たとえ n が負の値であっても、 次の暗黙のキーは n+1 を使うようになります。

  • デフォルトの error_reporting のレベルは E_ALL になりました。 これより前のバージョンでは、 E_ALL から E_NOTICEE_DEPRECATED が除かれていました。

  • display_startup_errors は、 デフォルトで有効になりました。

  • 親クラスがないクラスの内部で parent を使うと、 致命的なコンパイルエラーが発生するようになりました。

  • @ 演算子は、致命的なエラー (E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR, E_PARSE) を隠さなくなりました。 @ を使う時に、 error_reporting が 0 であることを期待しているエラーハンドラは、 代わりにマスクチェックを調整すべきです:

    <?php
    // こういうエラーハンドラは
    function my_error_handler($err_no, $err_msg, $filename, $linenum) {
    if (
    error_reporting() == 0) {
    return
    false;
    }
    // ...
    }

    // 以下に置き換えましょう
    function my_error_handler($err_no, $err_msg, $filename, $linenum) {
    if (!(
    error_reporting() & $err_no)) {
    return
    false;
    }
    // ...
    }
    ?>

    さらに、実運用環境で表示されていなかった、 情報のリークに繋がるエラーメッセージにも注意を払うべきです。 エラーのロギングと併せて、 display_errors=Off となっていることを確認するようにして下さい。

  • #[ は、コメントの開始として解釈されなくなりました。 この文法は、アトリビュート として使われるようになっているからです。

  • 非互換なメソッドのシグネチャによる継承エラー(リスコフの置換原則違反)については、 常に致命的なエラーが生成されるようになりました。 これより前のバージョンでは、警告が生成される場合がありました。

  • ビットシフトや加算、減算に対する連結演算子の優先順位が変更されました。

    <?php
    echo "Sum: " . $a + $b;
    // 上記は、以前のバージョンでは以下のように解釈されていました:
    echo ("Sum: " . $a) + $b;
    // PHP 8.0.0 からは、以下のように解釈されます:
    echo "Sum:" . ($a + $b);
    ?>

  • 実行時に null に解決されるデフォルト値を持つ引数は、 引数の型を暗黙のうちに nullable とマークすることはなくなりました。 明示的に nullable と宣言するか、 明示的にデフォルト値を null と宣言しなければなりません。

    <?php
    // 以下のようなコードは
    function test(int $arg = CONST_RESOLVING_TO_NULL) {}
    // このように置き換えるか
    function test(?int $arg = CONST_RESOLVING_TO_NULL) {}
    // こう書きましょう
    function test(int $arg = null) {}
    ?>

  • たくさんの警告が Error 例外に変換されるようになりました:

    • オブジェクトでない値にプロパティを書き込もうとした場合。 これより前のバージョンでは、 null については stdClass オブジェクトが暗黙のうちに作られ、 空文字列については false となっていました。
    • PHP_INT_MAX キーが既に使われている配列に対して、 要素を追加しようとした場合。
    • 不正な型(配列やオブジェクト) を配列のキーや文字列のオフセットとして使おうとした場合。
    • スカラー値に配列のインデックスを書き込もうとした場合
    • 配列やTraversable でない値をアンパックしようとした場合
    • 未定義の、非修飾の定数にアクセスしようとした場合。 これより前のバージョンでは、 非修飾の定数にアクセスしようとすると、警告が発生し、 文字列として解釈されていました。
    • 可変長引数でない組み込み関数に、間違った数の引数を渡した場合、 ArgumentCountError がスローされるようになりました。
    • 無効な countable 型を count() に渡した場合、 TypeError がスローされるようになりました。

    多くの notice が警告に変換されるようになりました:

    • 未定義の変数を読み取ろうとした場合
    • 未定義のプロパティを読み取ろうとした場合
    • 未定義の配列のキーを読み取ろうとした場合
    • オブジェクトでない値のプロパティを読み取ろうとした場合
    • 配列でない値のインデックスにアクセスしようとした場合
    • 配列を文字列に変換しようとした場合
    • リソースを配列のキーとして使おうとした場合
    • null や bool 値や float の値を文字列オフセットとして使おうとした場合
    • 境界を超えて文字列のオフセットを読み取ろうとした場合
    • 文字列のオフセットに空文字列を割り当てようとした場合

  • 文字列のオフセットに複数バイトを割り当てようとすると、警告が発生するようになりました。

  • ソースファイル中に(文字列の範囲外のNUL バイトのような) 想定外の文字が含まれていた場合、 コンパイル時に警告を出す代わりに、 ParseError がスローされるようになりました。

  • 例外がキャッチされなかった場合、 "クリーンなシャットダウン" が行われます。 これは、例外がキャッチされなかった後、 デストラクタが呼ばれるということです。

  • コンパイル時の致命的なエラー "Only variables can be passed by reference" は、 実行時まで遅延され、 "Argument cannot be passed by reference" という Error 例外に変換されるようになりました。

  • "Only variables should be passed by reference" という警告は、 "Argument cannot be passed by reference" という例外に変換されるようになりました。

  • 無名クラスのために生成される名前が変更されました。 最初の親クラスやインターフェイスの名前が含まれるようになっています:

    <?php
    new class extends ParentClass {};
    // -> ParentClass@anonymous
    new class implements FirstInterface, SecondInterface {};
    // -> FirstInterface@anonymous
    new class {};
    // -> class@anonymous
    ?>

    上で示した名前の後に、NULバイトやユニークなサフィックスが続きます。

  • トレイトのエイリアス調整において、 クラス名を指定していないメソッド参照は、 曖昧でないことが必須になりました:

    <?php
    class X {
    use
    T1, T2 {
    func as otherFunc;
    }
    function
    func() {}
    }
    ?>

    T1::func()T2::func() が両方存在している場合、 PHP 8.0.0 より前のバージョンでは、 このコードは黙って動作し、func は T1::func を参照するものと想定されていました。 PHP 8.0.0 からは、このコードは致命的なエラーが発生します。 T1::func または T2::func を明示的に書く必要があります。

  • トレイトで定義される抽象メソッドのシグネチャは それを実装するクラスのメソッド側で、 一致しているかがチェックされるようになりました:

    <?php
    trait MyTrait {
    abstract private function
    neededByTrait(): string;
    }

    class
    MyClass {
    use
    MyTrait;

    // エラー。戻り値の型が一致しません。
    private function neededByTrait(): int { return 42; }
    }
    ?>

  • 無効にされている関数は、存在しない関数であるかのように扱われるようになりました。 無効にされている関数を呼び出しても unknown と報告されますし、 無効にされている関数を再定義することも可能になっています。

  • data:// ストリームラッパーは書き込み可能ではなくなりました。 これは、ドキュメント化されている振る舞いに一致します。

  • 算術演算子とビット演算子 +, -, *, /, **, %, <<, >>, &,