PHP
マイグレーション
PHP7
PHP7.2
PHP7.3
PHPDay 19

PHP7.2から7.3へのマイグレーションガイド

PHP公式のマイグレーションガイドがまだ日本語訳されていない。

PHP 7.2.x から PHP 7.3.x への移行

このマイナーバージョンアップには数多くの新機能があります。
また、互換性がない変更 が多少あるので、実運用環境のPHPをこのバージョンにあげる前にはテストすべきです。

新機能

PHP7.3の新機能。

More Flexible Heredoc and Nowdoc Syntax

フレキシブルなヒアドキュメント。
詳細はこちら

Array Destructuring supports Reference Assignments

分割代入およびlistがリファレンスを受け付けるようになった。
詳細はこちら

[&$a, [$b, &$c]] = $d;

Instanceof Operator accepts Literals

instanceofの左辺がリテラルを受け入れる

    var_dump( 1 instanceof stdClass ); // false

ただし値は常にfalseになる。
いったい何の意味があるのかはよくわからない。

CompileError Exception instead of some Compilation Errors

ParseErrorErrorの間にCompileErrorが追加された。
現在はtoken_get_allでTOKEN_PARSEフラグを使った際にしか発生しないが、今後増える可能性はある。

Trailing Commas are allowed in Calls

関数呼び出しの末尾カンマが許可される。
詳細はこちら

Argon2id Support

password_hash関数の対応アルゴリズムにArgon2idが追加される。
詳細はこちら

FastCGI Process Manager

ロギングのカスタマイズ用パラメータlog_limit、log_buffering、decorate_workers_outputが追加された。

log_limit

1行の文字数制限を指定する。

log_buffering

バッファを使わない実験的なログ書き出しを許可する。

decorate_workers_output

catch_workers_outputが有効なときにログに出力される文字列装飾を無効化する。

BC Math Functions

bscaleの引数がオプションになる。
返り値の型はboolからintになり、変更前のscale値が入ってくる。
詳細はこちら

Lightweight Directory Access Protocol

LDAP関数の引数にLDAP Controlsが追加された。
詳細はこちら

Full Case-Mapping and Case-Folding Support

マルチバイト関数において、完全なケースマッピングがサポートされた。
詳細はこちら

var_dump(mb_strtoupper("Straße"));
    // STRASSE >=7.3
    // STRAßE  < 7.3

Case-Insensitive String Operations use Case-Folding

大文字小文字を区別しない関数が、文字列比較においてこれまでのcase-mappingではなくCase-Foldingを使うようになる、というようなことが書かれているようなのだが、どうもそうは見えない気がしてよくわからない。

MB_CASE_TITLE performs Title-Case Conversion

mb_convert_caseにMB_CASE_TITLEを渡したときの挙動が変更になる。
のだが、Cased and CaseIgnorable derived Unicode propertiesというのが何なのかわから。
特にクオートやアポストロフィーが改善されるとも書いてあるのだが、特に変化が無いように見える。

Unicode 11 Support

Unicode 11をサポートした。

Long String Support

マルチバイト関数が2GB以上の文字列を扱えるようになった。
関数は耐えてもサーバが死にそう。

Performance Improvements

マルチバイト関数のパフォーマンスが大幅に上昇した。
これは新機能に書くようなことなのだろうか?

Named Captures Support

mb_ereg系の正規表現が名前付きキャプチャに対応した。

mb_regex_encoding("UTF-8");
mb_ereg('(?<year>\d+)-(?<month>\d+)-(?<day>\d+)', '2018-12-31', $matches);
var_dump($matches);

/*
array(7) {
  [0]=>
  string(10) "2018-12-31"
  [1]=>
  string(4) "2018"
  [2]=>
  string(2) "12"
  [3]=>
  string(2) "31"
  ["day"]=>
  string(2) "31"
  ["year"]=>
  string(4) "2018"
  ["month"]=>
  string(2) "12"
}
*/

7.3未満の場合は同じ正規表現でもエラーにはならないが、単に無視されてyear/month/dayが入ってこない。

またmb_ereg_replace\k<>で名前付きキャプチャを参照できる

Readline

readline_infoにパラメータcompletion_append_charactercompletion_suppress_appendが追加された。
libeditではなくlibreadlineを使っている場合のみ使用可能。

新しい関数

PHP7.3で増えた関数、およびメソッド。

array_key_first() / array_key_last()

配列のキーを取得する関数。
詳細はこちら

hrtime()

ナノ秒単位の時刻を取得する関数。
詳細はこちら

is_countable()

count()できるかどうかを判断する関数。
詳細はこちら

net_get_interfaces()

ネットワークインターフェイスを取得する関数。
詳細はこちら

fpm_get_status()

FastCGIの情報を取得できるみたいだが、英語版ドキュメントすらまだなく、近場にFastCGI環境がなかったので詳細不明。
このような出力になるようだ。

DateTime::createFromImmutable()

DateTimeImmutableからDateTimeを生成する。
詳細はこちら

gmp_binomial() / gmp_kronecker() / gmp_lcm() / gmp_perfect_power()

gmpに二項分布、クロネッカー関数、最小公倍数、累乗数が追加された。
詳細はこちら

Normalizer::getRawDecomposition() / normalizer_get_raw_decomposition() / Spoofchecker::setRestrictionLevel()

UTF-8文字列のDecomposition Mappingプロパティを取得するらしいのだが、何のことだかさっぱりわからない
を手元で試してみたら、全て"no decomposition mapping"と言われてしまった

ldap_add_ext() 他8関数

LDAP関連関数が8
それぞれextの付かない関数と同じだが、返り値がリソースになる。

openssl_pkey_derive()

公開鍵暗号の共有鍵を生成する。
詳細はこちら

socket_wsaprotocol_info_export() / socket_wsaprotocol_info_import() / socket_wsaprotocol_info_release()

何も情報が無いので詳細不明。
テストでも特に有用なことが書かれていない。
試してみたところではsocket_wsaprotocol_info_exportすると"php_wsa_for_1"のような文字列が得られ、それをsocket_wsaprotocol_info_importに渡すとSocketリソースに戻った。
Socketの永続化というイメージでいいのだろうか。

新しいグローバル定数

定数が100以上増えていてとても多いのだが、ほとんどは外部ライブラリの定数をPHPでもそのまま使えるようにしているだけのようだ。

PASSWORD_ARGON2ID

password_hash関数のハッシュアルゴリズムArgon2idを表す定数。
詳細はこちら

CURLAUTH_BEARER 他79定数

Curl関連の定数がやたら増えた。
単にlibcurlのオプションをそのまま持ってきただけ。

FILTER_SANITIZE_ADD_SLASHES

FILTER_SANITIZE_MAGIC_QUOTESと同じ。
詳細はこちら

JSON_THROW_ON_ERROR

json_decodeに失敗したときに例外を出すようにする。
詳細はこちら

LDAP_CONTROL_ASSERT 他26定数

LDAP定数もやたら増えた。
こちらもLDAPの定数を持ってきただけのようだ。

MB_CASE_FOLD / MB_CASE_LOWER_SIMPLE / MB_CASE_UPPER_SIMPLE / MB_CASE_TITLE_SIMPLE / MB_CASE_FOLD_SIMPLE

mb_convert_caseなどで指定する変換モード。

STREAM_CRYPTO_PROTO_SSLv3 / STREAM_CRYPTO_PROTO_TLSv1_0 / STREAM_CRYPTO_PROTO_TLSv1_1 / STREAM_CRYPTO_PROTO_TLSv1_2

SSLストリームに接続する際のTLSバージョンを限定する定数。
stream_context_createの第二引数コンテキストパラメータに渡す。

PGSQL_DIAG_SCHEMA_NAME 他6定数

PostgreSQLのPGSQL_DIAG_SCHEMA_NAME等をそのまま持ってきた。

下位互換性のない変更点

Heredoc/Nowdoc Ending Label Interpretation

ヒアドキュメントのシンタックス改善に伴い、これまで問題なかったテキストがエラーになる可能性がある。
詳細はこちら

$str = <<<FOO
   FOO
FOO;
// 7.3ではParse error、7.2まではOK

Continue Targeting Switch issues Warning

Switch内でcontinueを使うとE_WARININGが発生する。

while ($foo) {
    switch ($bar) {
      case "baz":
         continue;
   }
}

このcontinueはswitchからの脱出を表しておりbreakと同じ意味だった。
他言語では『次のwhileに進む』を表すことが多いので、混同を避けるため警告を出すようにしたようだ。
"continue 2"は問題なく動作する。

Strict Interpretation of Integer String Keys on ArrayAccess

ArrayAccessを実装したクラスのオブジェクトに$obj['1']とアクセスした場合、offsetGetの引数には自動型変換により数値1が渡されていた。
今後は型変換しないようになる。

class Test implements ArrayAccess {
  public function offsetGet($index){
      var_dump($index); // 7.3では'1'、7.2までは1
  }
}

$test = new Test();
$test['1'];

通常の配列は今までどおり自動型変換されるので注意。

Static Properties no longer separated by Reference Assignment

これまではpublic staticプロパティを親クラスと子クラスで異なる値にすることができるという裏技があったのだが、この抜け穴が塞がれた。

class Test {
    public static $x = 0;
}
class Test2 extends Test {}

Test2::$x = &$x;
$x = 1;

var_dump(Test::$x, Test2::$x); // 7.3では『1, 1』、7.2までは『0, 1』

裏技つーかバグだな。

References returned by Array and Property Accesses are immediately unwrapped

ひとつの式でリファレンスに値を設定しつつ同時に使用した場合の動作が変更される。

$arr = [1];
$ref =& $arr[0];
var_dump($arr[0] + ($arr[0] = 2)); // 7.3では3、7.2までは4

リファレンスを使わなければ問題は起こらないので問題は無い。

Argument Unpacking of Traversables with non-Integer Keys no longer supported

Traversableが非整数キーの配列を返してきた場合、それを直接...に入れるとエラーが出るようになった。

function gen() {
    yield 1.0 => 2;
}
var_dump(...gen()); // 7.3ではFatal error、7.2までは2

これまで動作していたのは偶然らしい。

Miscellaneous

ext_skelが刷新された。
PHP製になり、外部依存がなくなった。つまりWindowsでも動作する。

BeOSがサポートされなくなった。

エラーハンドリングのEH_THROWモードについて、通常の例外と同様にerror_get_lastを出力しないようになった。
EH_THROWはエラーを例外に変換するという内部フラグで、たとえばDateTimeが使っている。

try{
    new \DateTime("aa");
}catch(\Exception $e){
    var_dump(error_get_last()); // 7.3ではnull、7.2までは値が入っている
}

TypeErrorで表示されるメッセージの型が、これまで『integer』『boolean』だったのが『int』『bool』になった。
なんで?

new SplFixedArray('a');
    // 7.3はexpects parameter 1 to be int, string given
    // 7.2まではexpects parameter 1 to be integer, string given

compactが存在しない変数にE_NITOCEを出すようになった。
詳細はこちら

getimagesizeがこれまでBMP画像に"image/x-ms-bmp"を返していたのを、今後は"image/bmp"を返す。

stream_socket_get_nameで返ってくるIPv6アドレスに大括弧が入るようになる。
たとえばこれまで::1:1337だったものが[::1]:1337になる。

BCMath Arbitrary Precision Mathematics

BCMathのエラーが全てPHPでハンドリングされるようになった。
以前は一部のエラーが直接stderrに出力されていた。

bcpow('1', '12345678901234567890');
    // 7.3ではE_WARNING
    // 7.2まではbc math error

bcmulbcpowが第三引数の小数点以下桁数を律儀に守るようになった。
これまでは不要なら省略していた。

var_dump(bcpow('1234567890', '1', 2));
    // 7.3では"1234567890.00"
    // 7.2までは"1234567890"

IMAP, POP3 and NNTP

rshおよびsshで接続するIMAP設定オプションimap.enable_insecure_rshが追加され、デフォルトが無効になった。
無効にしないとセキュリティの問題があるみたいなんだけどよくわからない。

Multibyte String

名前付きキャプチャに対応したので、mb_ereg*関数の結果が変わる可能性がある。

MySQL Improved Extension

プリペアドステートメントがDATETIME、TIME、TIMESTAMP型の小数点以下桁数を正しく処理するようになった。

MySQL Functions (PDO_MYSQL)

PDO::ATTR_EMULATE_PREPARES=falseの場合、プリペアドステートメントについて同上。
PDO::ATTR_EMULATE_PREPARES=trueの場合は元々適切な処理を行っていたので影響を受けない。

Reflection

Reflectionで表示される型が、これまで『integer』『boolean』だったのが『int』『bool』になった。

ちなみにgettypeは『integer』『boolean』のまま。

Standard PHP Library (SPL)

SPLのオートロードが例外を出した場合、オートロードはそこで中断される。
これまではその後のオートロードも実行されていた。

SimpleXML

SimpleXMLオブジェクトを計算式に突っ込んだ場合、値を適切な型で扱うようになった。
これまでは強制的に整数にされていた。

  $foo = new SimpleXMLElement('<foo>1.9</foo>');
  echo $foo * 3; // 7.3では5.7  7.2までは3

PHP 7.3.x で推奨されなくなる機能

7.3から非推奨になる機能。
今回からE_DEPRECATEDなどが発生するようになり、基本的に次のメジャーバージョンで削除される。

Case-Insensitive Constants

defineの第三引数、大文字小文字を区別しないオプションが削除される。
詳細はこちら

Namespaced assert()

名前空間内であろうともassert関数が定義できなくなる。
詳細はこちら

Searching Strings for non-string Needle

strposなどの検索関数に数値を渡してもコードポイントと解釈されなくなる。
詳細はこちら

Strip-Tags Streaming

fgetss、gzgetss、SplFileObject::fgetss、string.strip_tagsストリームフィルタが削除される。
詳細はこちら

Data Filtering

定数FILTER_FLAG_SCHEME_REQUIREDとFILTER_FLAG_HOST_REQUIREDが削除される。
詳細はこちら

Image Processing and GD

image2wbmpが削除される。
詳細はこちら

Internationalization Functions

Normalizer::NONEが削除される。
これはPHPではなくNormalizerの仕様のようだ。

Multibyte String

mb_ereg_**系関数のエイリアスmbereg_**が削除される。
詳細はこちら

ODBC and DB2 Functions (PDO_ODBC)

ディレクティブpdo_odbc.db2_instance_nameが削除される。
詳細はこちら

その他の変更

Set(raw)cookie accepts $option Argument

setcookieおよびsetrawcookieが配列形式の引数を受け取れるようになった。
詳細はこちら

setcookie('hoge', 'fuga', [
    'expires' => 3600,
    'path' => '/',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Strict',
]);

New Syslog ini Directives

error_logをsyslogにした際に、以下のディレクティブが使えるようになる。

syslog.facility

ファシリティコード番号

syslog.filter

メッセージフィルタ。現在は"all"・"no-ctrl"・"ascii"の3種類に対応。

syslog.ident

全てのメッセージの頭に付加される識別用文字列。

Garbage Collection

cyclic GCが強化されたため、パフォーマンスが大きく向上する可能性があるらしい。

Miscellaneous

var_export(object)キャストをそのまま出力するようになった。
これまではstdClass::__set_state()を出力していた。

var_export((object)'str');

// 7.3
(object) array(
   'scalar' => 'str',
)

// 7.2まで
stdClass::__set_state(array(
   'scalar' => 'str',
))

debug_zval_dumpvar_dumpで循環参照をどこまで表示するかの階層が異なっていたのだが、var_dumpの出力に揃えられた。

$a = new stdClass();
$a->a = &$a;

debug_zval_dump($a);

// 7.3
object(stdClass)#1 (1) refcount(2){
  ["a"]=>
  *RECURSION*
}

// 7.2
object(stdClass)#1 (1) refcount(2){
  ["a"]=>
  &object(stdClass)#1 (1) refcount(2){
    ["a"]=>
    *RECURSION*
  }
}

// var_dump 7.2も7.3も同じ
object(stdClass)#1 (1) {
  ["a"]=>
  *RECURSION*
}

array_pushおよびarray_unshiftの第二引数がオプションになった。
何も渡さない場合は何もしない。

Interactive PHP Debugger

未使用だった定数PHPDBG_FILE、PHPDBG_METHOD、PHPDBG_LINENO、PHPDBG_FUNCが削除された。

FastCGI Process Manager

FastCGIでgetallheadersが使えるようになった。
マニュアルでは5.4.0で使えるようになったとか書いてあるのだが全くそんなことはなく、2012年に出されたバグレポが今回ようやくマージされた

Client URL Library

libcurl 7.15.5以上が必須になった。

Data Filtering

FILTER_VALIDATE_FLOATが1000の位区切りを指定するthousandオプションをサポートしている。
デフォルトの',.はこれまでと互換性がある。
と書いてあるのだがFILTER_FLAG_ALLOW_THOUSANDは昔からあったような?

フィルタFILTER_SANITIZE_ADD_SLASHESがFILTER_SANITIZE_MAGIC_QUOTESのエイリアスとして追加された。
FILTER_SANITIZE_MAGIC_QUOTESは今後削除される可能性がある。

FTP

デフォルトの転送モードがバイナリになった。

Internationalization Functions

ICU56以降を使用している場合、Normalizer::NONEがDeprecatedになる。
またNormalizer::normalizeの引数としてNormalizer::FORM_KC_CFが使えるようになる。

JavaScript Object Notation

json_decodeおよびjson_encodeのオプションJSON_THROW_ON_ERRORが追加された。
なおJSON_THROW_ON_ERRORよりもJSON_PARTIAL_OUTPUT_ON_ERRORが優先される。

Multibyte String

configureオプション--with-libmbflが削除された。

ODBC (Unified)

ODBCRouterとBirdstepのサポートが廃止された。

OPcache

opcache.inherited_hackディレクティブが削除された。
実際にはPHP5.3以降無視されていた

OpenSSL

SSLストリームでmax_proto_versionおよびmin_proto_versionオプションに対応した。

Regular Expressions (Perl-Compatible)

Perl互換正規表現がPCRE2にアップグレードされた。
詳細はこちら

preg_quote#をエスケープするようになった。

Microsoft SQL Server and Sybase Functions (PDO_DBLIB)

空行をスキップするPDO::DBLIB_ATTR_SKIP_EMPTY_ROWSETSオプションが追加された。
TDSバージョンを取得するPDO::DBLIB_ATTR_TDS_VERSIONオプションが追加された。
DATETIME2型はDATETIME型と同じように扱われるようになった。

SQLite Functions (PDO_SQLITE)

データベースを読み取り専用で開く[PDO::SQLITE_ATTR_OPEN_FLAGS=>PDO::SQLITE_READONLY]オプションが追加された。

Session Handling

session_set_cookie_paramsが配列形式引数を受け取れるようになった。

session_set_cookie_params([
    'lifetime' => 3600,
    'path' => '/',
    'domain' => '.php.net',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Strict',
]);

samesiteにはLaxおよびStrictを指定できる。

ディレクティブsession.cookie_samesiteが追加された。
デフォルトは""で、これまでと同じ動作。

Tidy

tidypでも動くようになった。
ただしリリース日を返すAPIが無いためtidy::getReleaseは"unknown"を返す。

XML Parser

libxmlを使用している場合でもxml_set_external_entity_ref_handlerのコールバックの返り値を評価するようになった。
これまでは単に無視されていた。

Zip

バンドルされているlibzipは古いのでビルドは勧められないが、--without-libzipを指定すればいまだに可能。

Zlib Compression

compress.zlibプロトコルラッパーに、圧縮レベルを指定できるzlib/levelコンテキストオプションが追加された。

Windowsサポート

More POSIX Conforming File Deletion

ファイルディスクリプタはデフォルトでread/write/deleteモードで開かれる。
これによって使用中のファイルを削除することが可能になる。
ファイル削除後は、そのファイルを開いているハンドルが全てクローズされるまで、同名のファイルを作ることはできない。

感想

新機能はこれまでに調べたことのある内容が大半でしたが、それ以外にも色々と細かい変化が多々ありますね。
非互換な部分も意外とたくさんありますが、現実的に問題が出そうなのはヒアドキュメントくらいではないでしょうか。

文字コード関連は正直さっぱりわからないので詳しい人頼んだ。