PHP7.4.0ベータ3は何処に行った？

2019/07/25、PHP7.4.0ベータ1が[リリースされました](https://www.php.net/archive/2019.php#2019-07-25-1)。
2019/08/08、PHP7.4.0ベータ2が[リリースされました](https://www.php.net/archive/2019.php#2019-08-08-1)。
2019/08/22、PHP7.4.0ベータ4が[リリースされました](https://www.php.net/archive/2019.php#2019-08-22-1)。

あれ？
ベータ3は何処？

internalでも[ベータ3飛ばされた？](https://externals.io/message/106430#106676)と聞かれていますが、「いや、PHPのバージョンスキップは誇りであり伝統なのだよ」とか返されています。
しかし[PHP7.3](https://wiki.php.net/todo/php73)でも[7.2](https://wiki.php.net/todo/php72)でも普通にベータ3は出ているので、何のことだかよくわかりません。
ただの冗談なのか？


PHP7.4.0は2019/07/22に仕様凍結され、それ以降は以降は基本的にバグ修正だけが行われています。
以下はPHP7.4.0ベータ4で修正されたバグの一部です。


## [Second file_put_contents in Shutdown hangs script](https://bugs.php.net/bug.php?id=78396)

シャットダウン関数内でひとつのファイルに2回file_put_contentsするとハングするというバグ。

```php
<?php
register_shutdown_function ('shutdown');
function shutdown () {
    file_put_contents ('/tmp/test.txt', "shutdown 1 \n", FILE_APPEND | LOCK_EX);
    file_put_contents ('/tmp/test.txt', "shutdown 2 \n", FILE_APPEND | LOCK_EX); // Process exited with code 137
    var_dump(file_get_contents("/tmp/test.txt"));
    exit;
}
```

[7.4.0α3で混入した](https://3v4l.org/WFR0R)ようです。
どんな原理で起こるのかさっぱりだけど、そもそも普通はこんな使い方しないから気付かないのも仕方ない気はする。


## [Broken file includes with user-defined stream filters](https://bugs.php.net/bug.php?id=78406)

自作ストリームフィルタを通すと[include](https://www.php.net/manual/ja/function.include.php)で[何故かシンタックスエラーが発生する](https://3v4l.org/jEMEE)というもの。

ベータ1とベータ2でだけ発生します。
原因は[このコミット](http://git.php.net/?p=php-src.git;a=commit;h=c2c5c9a973559b7ba9f84337c5f8078e59e98a91)で、自作ストリームフィルタを使うとphp_stream_statの値が正しくならないことがあるとかなんとか。
そしてどうやら原因をなおすのではなく[対症療法をやった](http://git.php.net/?p=php-src.git;a=blobdiff;f=main/main.c;h=d86502788710f7aa79d2660e200115a71adba6f9;hp=5822cbfa217b8a1e0e930fc7d2b3ac1fe083d68e;hb=b01824e596dd11d075d1f2c9af364d2fdabc4d17;hpb=bdf3fa8c3e171c32635a6df0d5b544629eecb951)みたいなので、もしかしたら今後もまたうっかり何か起こるかもしれません。


## [fstat mode has unexpected value on PHP 7.4](https://bugs.php.net/bug.php?id=78386)

↑に関連してなのかどうなのか、[fstat](https://www.php.net/manual/ja/function.fstat.php)がPHPバージョンによって異なる値を返してくるバグが発覚しました。

```php
$handle = popen('echo 12', 'r');
$stats = fstat($handle);
var_dump($stats['mode']); // 7.3までは4096、7.4ベータ2では33206
```

ただ環境に依るようで、3v4lでは[全部4480でした](https://3v4l.org/C7Nbr)。つまり3v4lではバグが起こりません。


## [Casting a DateTime to array no longer returns its properties](https://bugs.php.net/bug.php?id=78383)

DateTimeインスタンスを`(array)`キャストすると[何も出力しない](https://3v4l.org/IEOt0)バグ。

```php
var_dump((array) new \Datetime('2000-01-01')); // 7.3までは[date, timezone_type, timezone]、7.4.0αは[]
```

いやー、さすがにこれはどうなんだよ。

しかしPHP内部で使うのであればクラスのままでいいし、外に出すならJSONだけど[json_encodeは正しく動く](https://3v4l.org/UmW4E)から、実用的に問題になるような状況はあまり思いつかないです。

と思いきやSymfonyが内部的に配列を使っているらしいです。
そうなると連鎖的にLaravelが死んでPHPが終焉を迎えるので、修正しないわけにはいかないですね。


## [Assertion failure in openssl_random_pseudo_bytes](https://bugs.php.net/bug.php?id=78391)

openssl_random_pseudo_bytesに第二引数を渡すと死ぬ。

```php
openssl_random_pseudo_bytes(4,$b);
```

Segmentation faultが発生します。
なんで。

[diffが1文字](http://git.php.net/?p=php-src.git;a=blobdiff;f=ext/openssl/openssl.c;h=f566d4e6edbd2b34ff4d0a4f17d78145ba387595;hp=b8acb79f6ca4c907bb3c2318783fef2c252557b1;hb=699b465da20fcb25747b3e1bad2e9f84a9d6d8b0;hpb=1456467cfe19379150a06592d9362091d443d255)なんだけど、うっかりゴミ'/'が残っていただけなのだろうか。
しかもこれPHP7.1あたりからあったみたいです。


## [Cannot "manually" unserialize class that is final and extends an internal one](https://bugs.php.net/bug.php?id=78410)

より優れたシリアライズを提供する[VarExporter](https://symfony.com/components/VarExporter)なるSymfonyプラグインがあります。

ところが、これがPHP7.4で[`__serialize`/`__unserialize`が追加された](https://qiita.com/rana_kualu/items/993fff9662726a004660#new-custom-object-serialization-mechanism)せいで自力でのシリアライズ/デシリアライズが不可能になったとかなんとか。
具体的にはシリアライズに[ReflectionClass::newInstanceWithoutConstructor](https://www.php.net/manual/ja/reflectionclass.newinstancewithoutconstructor.php)を使っていて、そのヘルプには"組み込みfinalクラスはReflectionClass::newInstanceWithoutConstructorできない"と書かれているのですが、実際は組み込みクラスをextendsしたfinalクラスも[ReflectionClass::newInstanceWithoutConstructorできない](https://3v4l.org/AIAeQ)ので詰んだ(dead-end)そうです。
どういう理屈なのかいまいちよくわからないのですが、Nikitaもよくわからないとか言ってて、そしてよくわからないまま[解決していました](http://git.php.net/?p=php-src.git;a=commit;h=d891b5f458a253befaa56d325ae90518536fc2f0)。


## [Can't access OneDrive folder](https://bugs.php.net/bug.php?id=78220)

ローカルのOneDriveフォルダにglobやscandir、file_get_contentsなどでファイルアクセスが全くできないというバグ。

かつて[同じような問題があり修正された](https://bugs.php.net/bug.php?id=75384)のですが、[Windows 10 May 2019 Update](https://support.microsoft.com/ja-jp/help/4028685/windows-10-get-the-update)による仕様変更で再発したようです。

それにしても、たかだかファイルアクセスしたいだけなのに[めちゃめちゃ大変](https://github.com/php/php-src/blob/php-7.4.0beta4/Zend/zend_virtual_cwd.c#L484)だな。


# 今後の予定

2019/09/05にRC1、そして以後も2週間ごとにRCがリリースされ、正式版リリースは2019/11/28の予定です。


# 感想

発生すればクリティカルだけど、発生条件がややこしくて誰も気付かなかった、みたいなものが多いです。
また直近で発生したバグは、多くが別の変更に伴って発生したものです。
○○を高速化した → △△が発生した → △△を修正したら××が発生した、みたいなやつですね。

原因のひとつとしてソースコードの見通しが悪いという問題点があるのは間違いないので(あらゆるところで`#ifdef`の嵐だ)、もっとすっきりした書き方にした方がいいのではないかと思ったりはします。
が、しかしここは言語開発の世界です。
読みやすさなどより速度のほうが遙かに重要だ、ということなのでしょう。