🙌

今週の PHP 2022/11/12 〜 2022/11/18

2022/11/22に公開約6,400字

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

Internal

[RFC] [Discussion] Readonly class amendments - Externals

https://externals.io/message/119007

ディスカッションのタイトルは「Readonly class の修正」です。

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

そもそもは、Readonly class のオブジェクト指向における立ち位置のようなものが議論されていましたが、RFC としてまとまりました。

https://externals.io/message/118554

修正案1 通常クラスが、readonly クラスを継承できるようにする。

現状は Fatal Error になります。

readonly class A {}
class B extends A {}

普遍のメンバを持ちつつ、動的なプロパティを利用する振る舞いを足すことも出来るということで、DTOの共通クラスのような扱いが期待されているのかもしれません。

修正案2 readonly なプロパティは、クローン時に再初期化可能

参考コードはこちら

class Foo {
    public function __construct(
        public readonly DateTime $bar,
        public readonly DateTime $baz
    ) {}
 
    public function __clone()
    {
        $this->bar = clone $this->bar; // Works
        $this->cloneBaz();
    }
 
    public function cloneBaz()
    {
        $this->baz = clone $this->baz; // Also works
    }
}
 
$foo = new Foo(new DateTime(), new DateTime());
$foo2 = clone $foo;
 
// No error, Foo::$bar and Foo::$baz are cloned deeply

clone 時にプロパティの値をいじれるようにする。ということでいいのかな。

https://3v4l.org/jHadc#v8.2rc3

サンプルを書いてみましたが、もちろん 8.2 系では動作しません。Cannot modify readonly property が出ます。
再初期化は __clone 内でのみ可能というルールのようです。

コレなんの意味があるの?というと、deep-clone 出来るようにするというのが意図のようです。
例えば、通常のクラスであれば、RFC のサンプルのように Datetime クラスのオブジェクトをプロパティに持つ場合は、__clone を使うことで deep-copy を行うことができます。

https://3v4l.org/uXjCl#v8.2rc3

object の ID が異なることに注目してください。readonly クラスではコレができません。つまり、同じオブジェクトを参照することになります。
何か困るのか?

readonly プロパティにセットされたのがミュータブルなオブジェクトの場合は、問題になりそうです。
つまり、clone 前後で同じオブジェクトを参照してしまうので、readonly なのに可変という状態になり、かつそれを阻止することができません。

ところで、なんで clone するんだろう... という疑問はさておき、修正内容については納得しました。

議論内では、現状の readonly クラスが LSP 違反であることも説明されていて、非常にためになる議論です。

Bugs

PHP unserialize bypass wakeup 8.1.1-fpm version · Issue #9936 · php/php-src

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

PHP-FPM で __wakeup が bypass されて実行されるという脆弱性について。
これって、修正されてなかったっけ?

https://www.php.net/manual/ja/language.oop5.magic.php#object.wakeup

wakeup は unserialize されたときに実行される関数です。

https://3v4l.org/Mvo9T

元になった脆弱性はこちら

https://bugs.php.net/bug.php?id=72663

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-7124

現行サポートの下限バージョンである、PHP 7.4 でも直っているはずのものではあります。

Fix GH-9883 SplFileObject::__toString() reads next line by Girgias · Pull Request #9912 · php/php-src

https://github.com/php/php-src/pull/9912

SplFileObject の __toString() メソッドが、次行を読み込んでしまう不具合の修正です。
fgets してたんですねぇ。

Session name with . or [ silently fails instead of giving warning/error · Issue #9932 · php/php-src

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

こんなものが残っているんですね! . または [ が含まられるセッション名だと、セッションが動かず、かつ Warning も Error も出ないという。

危ないやつなので、瞬殺されました。

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

次のリリースには入ると良いですね。

The behavior of mb_strcut in mbstring has been changed in PHP8.1 · Issue #9535 · php/php-src

https://github.com/php/php-src/issues/9535#event-7798348174

mb_strcut の挙動が ISO-2022-JP に対しておかしくなっていた件ですが、修正コミットがマージ。
これも、次のリリース。

特に ISO-2022-JP なんかは、使っているところがまだまだありそうなので、アップデート推奨。

preloading shutdown frees objects before module shutdown · Issue #9957 · php/php-src

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

preload している場合と、通常の場合で、object の解放と、モジュールのシャットダウンの順番が異なるというイシュー
実にありそうで、それでいて発見が難しそうなイシューです。

誰が見つけたのかと思ったら、 DataDog の tracer が rinit , rshutdown で動作しようとして SegV が出たということらしいです。
やはり、普通じゃないことをしないとこういうのは見つけられませんね。

unicode string corruption when using PDO_ODBC with FreeTDS 1.3.6 and MS SQL Server 2016 · Issue #9498 · php/php-src

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

Unicode 文字列が PDO_ODBC で崩れてしまうというイシュー。
FreeTDS は Sybase 系データベースのドライバーモジュールです。PHP から SQL Server に接続するときは、PDO_ODBC と FreeTDS という組み合わせで接続することになります。

select nchar というのは、ユニコード文字列に対応した SELECT 構文らしいのですが、音符記号が正常に取れてません。

影響を受けるユーザー数は少なそうですが、つらそうなイシューです。

cmb69 さんによると、 https://github.com/php/php-src/issues/9828 こちらの件が、根本原因になっているらしい。

そして...

I don't see a way to properly fix this, so we're unfortunately stuck. :(

というわけで、迷宮入り。

その昔、FreeTDS 周りは、少し調べたことがあるので、もしかしたら、自分でもなにか手伝えるかもしれないので、9828 は詳しく見てみよう。

Promote unserialize() notices to warning by TimWolla · Pull Request #9629 · php/php-src

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

2/3 が可決されました。

というわけで、さっそくマージされています。8.3 向けの Feature ですね。

https://github.com/php/php-src/pull/9629

PHP 8.1 bug, segfault executing Wordpress plugin code · Issue #9961 · php/php-src

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

8.1 で Wordpress のプラグイン実行時に SegV とのこと。該当の Wordpress のコードは普通の DB接続に見えます。一体何が原因なのか?

https://github.com/php/php-src/issues/9962#event-7819749863

Mixedな戻り値に対して、呼び元で型指定出来るようにしようよ!というイシュー

記法としては Alias みたいなやつですね。RFCを出してねで終了。

class A{}
$var = serialize(new A());
$a = unserialize($var) as `\A::class;`

下は、現状で使える解決策のコード例です。
var コメントを使ったり、assert を使ったりすることで、IDE の補完や、型安全を保証できます。

https://3v4l.org/N5mm5#v8.1.12

Non-pure default arguments are mistakenly cached · Issue #9965 · php/php-src

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

Non-pure というのは、インスタンスに文字列結合した状態のことを指すようです。

https://3v4l.org/CNYqh

文字列結合をやめると、正常に動くようになります。

https://3v4l.org/3SU3D

Non-pure なはずなのに、pure と判断されるため、再評価されず static 変数がカウントアップされないということなのかな?

修正内容は、今の自分には理解できません。

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

Segmentation Fault during OPCache Preload in PHP 8.1+ · Issue #9968 · php/php-src

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

OPCache Preload の SegV 報告です。

再現コードも添付されており、実際に SegV が確認できます。

https://github.com/michdingpayc/preload-segfault-minimum-reproduction

Preload なのか、JIT の問題なのか。
JIT の問題の場合は設定で逃れることも可能だといいですね。

mb_ereg_search_pos fails test "start of string" when using mb_ereg_search_setpos · Issue #9970 · php/php-src

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

近年は、UTF8 オプションをつけた preg 関数を使うことが多いので、 mb_ereg_search_pos なんてあったっけ?という感じです。
そこに、使ったこともない mb_ereg_search_setpos が組み合わさっているので、理解が難しい。

mb_ereg は、鬼車が使われているので、正規表現のパターンも鬼車に準拠していそうですが、^ の解釈はどうなっているのか?
しばらく観察します。

Use fast text conversion filters to implement mb_convert_variables by alexdowad · Pull Request #9966 · php/php-src

https://github.com/php/php-src/pull/9966#pullrequestreview-1184422316

mb_convert_variables の速度改善のようです。
行われている内容は、まじでよくわからない。やはり Valgrind が必要なのか......

Discussion

ログインするとコメントできます