🗂

今週の PHP 2022/07/30 〜 2022/08/05

2022/08/06に公開

PHP のメーリングリストから、気になった情報をピックアップします。

Internal

https://externals.io/message/118310

文字列が JSON かどうかを判定する is_json 関数の提案です。

  • json_decode とエラー補足を行うことで現状でも達成できる
  • json_decode はオブジェクト生成を行うし、memory_limit を突破してエラーになるリスクがある
  • 文字列が json かどうかだけ知りたいときがある

というあたりが RFC の動機だったようです。JSON 形式チェックを短時間に大量に行うようなケースであれば、効率が良くなりそうです。
※ 実際に RFC を提出した方の会社では JSON 形式チェックを大量に行う必要があって、memory 使用量やパフォーマンスで懸念がでていたそうです。

NO も YES も意見が出てきています。

結局形式チェック時に文字列をメモリにロードしなきゃいけないから、同じでは?
PoC を見せてほしいという意見

投稿主は、 memory_get_usage で前後のメモリ使用量を出しているが、 memory_get_peak_usage で実際にメモリ使用量が下がっていることを確認してほしいとう意見

関数名は is_json_valid がいいのでは?という意見

json_decode に Validation のみを行うフラグをオプションで追加したら?という意見

この関数は、本当に使いみちがあるのか? json_decode しないで、json 形式であることだけを確認したいなんてことあるのか?

もし、memory_limit より大きい文字列が json かどうかを判定できるなら、YES に入れるよ。といった意見

APIサーバーで、payload が json かどうかを事前チェックする用途なら理解できる。という意見

ユーザーランドでの実装は、Laravel, Symfony などでたくさん行われており、より軽快に動作する組み込み関数は、実際に必要とされていそう。

filter_var($possibleJSON, FILTER_VALIDATE_JSON)

こういうのはどうだろうか?という提案も

いずれにしろ、議論は活発に行われて、目的も明確になってきたので、RFC が提出されそうです。

PoC はまだ出てないのですが、イシュー主のベンチマークでは、 is_json のメモリ使用量は json_decode と比べても最小で済むようです。ベンチマーク上は、ほとんどメモリ使用量が増えていませんでした。

array_merge() vs array unpacking performance

https://3v4l.org/v5m9f#v8.1.8

3v4l はちょっとした計測エビデンスにも使えますね。

[...$arg1, ...$arg2]

PHP 8.0.22 Released

8.0.22 https://www.php.net/ChangeLog-8.php#8.0.22
8.1.9 https://www.php.net/ChangeLog-8.php#8.1.9

8.2.0 Beta 2

xoshiro** edge case

All zero state

-> bug fix 側で修正が出てる

https://en.wikipedia.org/wiki/Xoroshiro128%2B

乱数の世界は、とにかく知らない単語が多い。

XOR して Shift して Rotate するので、 Xoroshiro らしい。


Bugs

The last item of list variable will be error when use reference of variable. · Issue #9204 · php/php-src

https://github.com/php/php-src/issues/9204

foreach で Reference を使った際の挙動に対するイシュー

https://3v4l.org/FNVNL

なぜ、1 2 3 4 にならないのか?これについては、公式マニュアルにも記載があります。

https://www.php.net/manual/en/control-structures.foreach.php

意図通りに動いてもらうには

  1. unset を使う
    https://3v4l.org/nMXP7

  2. 変数名変える
    https://3v4l.org/8v1fI

細かく解説すると

$it には $list[3] の Reference がセットされています。つまり、2回目の foreach は継続的に $list[3] の内容を表示しています。
ループが回るに従って、$list[3] の内容が上書きされるため、最終的に key = 3 の内容が表示されるときには、一個前の 3 がセットされているので、1 2 3 3 と表示されます。

0 => [1, 2, 3, 1]
1 => [1, 2, 3, 2]
2 => [1, 2, 3, 3]
3 => [1, 2, 3, 3]

foreach で参照を使う場合は、空間計算量(メモリ)節約が一番の理由になりそうですが、上記のような挙動を考慮して書かないと、不具合を生む原因になりますね。

Obnoxious error in build/gen_stub.php "PHPDoc param type is unnecessary" · Issue #9183 · php/php-src

https://github.com/php/php-src/issues/9183

php-src の build/gen_stub.php における PHPDoc param type が面倒くさいので消したいというイシュー

そもそも gen_stub.php の役割が分かっていないのですが、議論の結果として、Annotation の @param チェックが削られてマージされています。

https://github.com/php/php-src/commit/98b858e756f9a04a7833dafa316005188f9b5c11

test とか実行するときの stub なんでしょうね。多分、phpt とかの実行してみると、役割が明確にわかりそうな気がする。

https://speakerdeck.com/hgsgtk/learn-php8-by-reading-phpt

というわけでやってみよう。

make test TESTS=ext/xml/tests/xml001.phpt

こんな感じで、テストを実行してみると、build/gen_stub.php がコールされていることが分かりました。というわけで、テストで必要な共通な関数群、定数郡を定義するためのファイルでした。
今回の話については、 setType 関数が引数の型チェックをしている箇所で、@param までチェック対象だと、メンテがつらいということらしい。

この辺は、コミッターの人たちじゃないと、気持ちは分かりづらそう。

Randomizer::pickArrayKeys() has intransparent external behavior · Issue #1731 · php/doc-en

https://github.com/php/doc-en/issues/1731

master に対するイシューとして上がってきている。
しかし、array_rand を使ってみると、7.1 以降は同じ挙動になっていることがわかる。

https://3v4l.org/g0uNE

というわけで、ドキュメント修正ということに。

setcookie has an obsolete expires date format · Issue #9200 · php/php-src

https://github.com/php/php-src/issues/9200

setcookie の日付形式がおかしいのでは?というイシュー

<?php
setcookie('expires-format-test', 'test', strtotime('now + 1 minute'));
Set-Cookie | expires-format-test=test; expires=Sat, 30-Jul-2022 05:12:54 GMT; Max-Age=60

RFC2616 のフォーマットの場合、以下の3つ

Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format

これに乗っ取るとすれば、 日付形式のハイフンは違反では?と

これに対する返信は

https://www.rfc-editor.org/rfc/rfc9110#section-5.6.7

https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.1

このあたりでは、ハイフン付きの日付も許容されると書いてあり、違反ではないと。
ハイフンがない日付のほうが、仕様としては新しいが、これは緊急で直す案件ではないと。

この辺、RFC の相関関係とか歴史を知っておかないと、迷子になりそうな議論でした。

Function for getting first or last value from array · Issue #9199 · php/php-src

https://github.com/php/php-src/issues/9199

array_key_first
array_key_last

を使いましょうね。

この関数、どのタイミングで入ったんだろうと思って RFC を確認したら

https://wiki.php.net/rfc/array_key_first_last

PHP 7.3 からでした。

Language change じゃないから、50% + の Vote でOKという記述があって、Vote率は内容によって違うのか〜〜〜っという発見でした。

dl() breaks expectations regarding permanent or interned strings · Issue #9196 · php/php-src

https://github.com/php/php-src/issues/9196

関連イシュー
https://github.com/php/php-src/issues/8508

dl() 関数が、内部文字列周りで不具合を起こすというイシュー。

precision 0 -INF · Issue #9209 · php/php-src

https://github.com/php/php-src/issues/9209

何を言ってるのかよくわからないと思ったが、要するに precision 0 を設定した状態で、INF に引き算した結果が、PHP 8.1 系から変わっているんだが??というやつ

damianwadley さんがまとめてくれていた。

Starting with PHP 8.1.0, when precision=0, -INF serializes to "-". Negative numbers are unchanged.

https://3v4l.org/S7mjm

そもそも、ini の precision とは?

https://www.php.net/manual/ja/ini.core.php#ini.precision

浮動小数点数に関して表示される最大桁数を指定します。 -1 は、数値を丸める際に拡張アルゴリズムを用いることを意味します。

ぴんとこねぇ。

Enum case as Array key? · Issue #9208 · php/php-src

https://github.com/php/php-src/issues/9208

Enum を Array の key にしたいよ!という話

すでに RFC もでていた

https://wiki.php.net/rfc/object_keys_in_arrays

それがなぜ問題なのかを指摘しているコメント

https://github.com/php/php-src/pull/6588#issuecomment-780545671

StreamWrapper support for glob() · Issue #9224 · php/php-src

https://github.com/php/php-src/issues/9224

glob は使ったことがありませんでした。

PHP: glob - Manual

macOS だと csh では使えました。
glob.h を include すれば C言語でも使えますね。パターンマッチするパス名を探してくれるコマンドです。

パス名?だから StreamWrapper に対応するべきものなのかどうか、私には判断がつきません。

そもそも StreamWrapper とは?

Brace expansions for fnmatch() · Issue #9223 · php/php-src

https://github.com/php/php-src/issues/9223

PHP: fnmatch - Manual

またしても、使ったことがない関数

fnmatch

https://3v4l.org/8XPvL#v8.1.8

なるほど、パターンマッチングができるんですね。

fnmatch も libc に含まれる関数のようで、PHP は C言語の薄いラッパーという概念を地で行く感じです。

このイシューですが、glob と fnmatch に brace expressions を追加するかどうか?という話です。

発端は、最近 python に入った以下の機能追加のようです。

bpo-9584: Added brace expressions to the glob and fnmatch. by matusvalo · Pull Request #6299 · python/cpython

https://github.com/python/cpython/pull/6299/files

diff を見ると イメージが凄くわきますね。

{pat1,pat2,...} このパターンで、pat1, pat2 を or でマッチさせることができるというものです。

csh で試してみると glob コマンドで

glob {composer.json,composer.lock}

composer.json と composer.lock の療法を引っ掛けることが出来ました。なので、PHP 側が対応していないということのようですね。

https://3v4l.org/GpRjD#v8.1.8

試してみましたが、今は使えないようです。このへんは使えるようになってもいいなと思いました。

Segfault in zend_accel_class_hash_copy · Issue #9164 · php/php-src

https://github.com/php/php-src/issues/9164

何を直しているんだか、全然わからねぇな!

https://github.com/php/php-src/pull/9188/files

私にわかるのはバグレポートが実に正確だということです。こういうバグレポートを私も書きたい。

trim support for multibyte spaces / mb_trim() · Issue #9216 · php/php-src

https://github.com/php/php-src/issues/9216

mb_trim !!!!

mbstring の拡張に入るらしい。しかし、全世界にはたくさんの空白があるんだねぇ。

Filenames with leading dots or spaces are not properly handled · Issue #9227 · php/php-src

https://github.com/php/php-src/issues/9227

Windows環境において、ファイル名の末尾にドットが入っていると、適切にファイルハンドリングされないという不具合。
こういう不具合がまだ残っているのですね。

Partially support first-class callable syntax in constant expressions · Issue #9236 · php/php-src

https://github.com/php/php-src/issues/9236

constant に 第一級 callable を設定できるようにしようというイシュー。
RFC プロセスのご案内

第一級 callable というのは、8.1 で追加された。callable から無名関数を生成する記法

https://3v4l.org/dhFam#v8.1.9

【Big BUG】Why 439!=4.39 * 100, But 438==4.38 * 100? · Issue #9243 · php/php-src

https://github.com/php/php-src/issues/9243

出ました。IEEE-754
定期的にイシューが寄せられる、浮動小数点関連です。小数点は近似計算になるということを覚えておきましょう。

https://ja.wikipedia.org/wiki/IEEE_754

https://3v4l.org/tMcPL#v8.1.9

Segfault with array_multisort + array_shift (packed arrays?) · Issue #9244 · php/php-src

https://github.com/php/php-src/issues/9244

<?php
$items = ['foo' => 1, 'bar' => 2];
$order = [4, 3];
array_multisort($order, $items);
var_dump(array_shift($items));

array_multisort と array_shift の組み合わせで、seg fault が起きるというイシュー。
8.2-dev なので、現状リリースされているバージョンには影響はなさそうです。

https://github.com/php/php-src/commit/ad04345eb34992f8f3f0ee310664e1848f3346b1

Fix の内容をみると sort したあとに zend_hash_rehash を行っていないことにより array_shift がセグフォを出すようです。

zend_hash_rehash のコードは今度追ってみようかな。

Assertion when fetching property of "bad" magic constant · Issue #9136 · php/php-src

https://github.com/php/php-src/issues/9136

マジックメソッドのプロパティを参照しようとしたときの、エラーメッセージがおかしいというもの

zend_compile.c:9852: zend_compile_const_expr_magic_const: Assertion `ast->attr == T_CLASS_C' failed.

Fixはこの2つ
https://github.com/php/php-src/commit/7b43d819c86cc96522bd9766126309f8a931faed
https://github.com/php/php-src/commit/966d22b1bdafd047cea89ddd04788367ea3be0a4


ext-Random周り

PcgOneseq128XslRr64::jump should not allow negative $advance · Issue #9212 · php/php-src

https://github.com/php/php-src/issues/9212

https://externals.io/message/118328

ext-Random の polyfill を書いている人からのイシュー。

PcgOneseq128XslRr64::jump() が負の整数を受け取ると、unsigned int にキャストされて整合性が取れなくなるので、負の整数を受け取らないようにしませんか?という提案

こちらはパッチ。例外スローが追加されている。

https://github.com/php/php-src/pull/9213/files

Random: Xoshiro256StarStar does not reject the invalid all-zero state · Issue #9249 · php/php-src

https://github.com/php/php-src/issues/9249

ext-Random のbug fix

https://github.com/php/php-src/commit/1cd2d731ef62b25165c45ae8475f4aa3fedb5f5b

不正な入力値や、暗合生成機が 0 を生成した場合に Retry するなどのコードが追加

More ext-random integer overflow · Issue #9190 · php/php-src

https://github.com/php/php-src/issues/9190

整数オーバーフローの修正。

https://github.com/php/php-src/commit/60ace13f9c5e2828bfa1c177479039f6abbd4319

いやー、どういうことだが、よくわからんですね。

MT_RAND_PHP causes undefined behavior · Issue #9191 · php/php-src

https://github.com/php/php-src/issues/9191

-> #9190 と同じFix

おまけ

https://thephp.foundation/blog/2022/07/28/php-core-roundup-4/

Discussion