🌀

今週の PHP 2022/08/06 〜 2022/08/12

2022/08/12に公開約7,000字

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

Internal

PHP: rfc:asymmetric-visibility

https://wiki.php.net/rfc/asymmetric-visibility

8.3 系に対する最初の RFC です。

object property に対する アクセス修飾子 public, private, protected で property の可視性を定めることが出来ます。
この可視性は、set get メソッドを実装した場合に同一であり、異なる可視性を指定することはできません。

この RFC は asymmetric。つまり set と get でそれぞれ異なる可視性を設定できるようにする提案です。

class Foo
{
    public private(set) string $bar;
}

Constructor Promotion でも使えるようにするようです。

上の例では、get は public、set は private になります。つまり

$foo = new Foo();

echo $foo->bar; //これはOK
$foo->bar = 'fuga'; //これはNG

Readonly クラスと違って、値のセットは何回でもできます。
__set の場合も、上記の可視性がそのまま適用されます。

今までの書き方に慣れている身としては、相当気持ち悪いプロパティ定義に見えますが、慣れの問題かな??

メモ

Swift では同様の言語仕様がある

https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html
名称はわからなかったけど、上記仕様書内にまさに public private(set) の記述があり、値の設定のみクラス内に限定させることができるとありました。

Reflection についての懸念点が上がってきています。つまり isPublic とか getModifiers とかしたときに、どう表現されるのか?ということです。
アクセス修飾子にプラスアルファの条件が追加されているので、きちんと設計しないとカオスになりそう。

C# style では駄目か?という話があった。おそらくこれのことだと思うけど

https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers
アクセス修飾子をいっぱい増やすことで、public private(set) に該当するようなやつを用意すればいいということかな。

この提案は、下記の3つのアクセスレベルを増やすことと同義

  • "public private(set)"
  • "public protected(set)"
  • "protected private(set)"
    ※この提案では、set のみが個別指定の対象となる public protected(get) のような書き方はない。

attribute でもできるのでは? public readonly などの書き方はどうか?
-> 見た目が自明であるし、Swift の文法に合わせたいので、元の提案通りで行きたい。

PHPStan/Psalm には @private @internal @phpstan-internal があるので、今回のような仕様変更がなくても補える。
そもそも、immutable な property をできるだけ維持したいので、今回のようなケースはレア。値を更新したかったら、Readonly のオブエジェクトをつく直せ。という意見も

それに対して、PHPStan/Psalm でサポートするなら、言語側で対応して、みんなに使ってもらおうよ!という意見。たしかに。

コメントが沢山ついていて、読むのも大変です。
Larry さんは、さらなるユースケースなどについて、コメントしたいということで、フォローアップを待っていてねということです。

RFC Idea - is_json - looking for feedback

今週もアイデア募集中です。

コメントが来ています。

  • filter_var はいいかもしれないけど、is_json のがグッとくるよね
  • is_json_valid の方が、認識の齟齬がないと思う

実装上の懸念としては、RFC の理由の一つとなっているメモリ使用量について。

  • 実際に文字列を parse せずに、正しい JSON であるかどうかを判断できるのか?
  • PCRE(正規表現) でやるんだろうけど、正確な実装ができるのか疑問

来週にも RFC を用意するということです。Karma Request が来たので、RFC の準備を始められたようです。

RFC Idea: Introducing a ReflectionWithAttributes interface - Looking for feedback

ReflectionWithAttribute Interface の提案です。

PHP に Attribute に追加されたのは、8.0 からです。
Reflection 関連で、Attribute をうまく扱うインタフェースを追加したいということのようです。

あったほうが良さそうですね。無理やりパースして取得みたいな羽目になるのはつらそうです。

[Concept] Extension methods

既存のクラスに対して、特定の機能を持つ関数を追加するような仕組みの導入提案です。

例としては Collection のようなクラスに map メソッドを追加しています。

(new Collection(1,2,3))
  ->map(fn ($value) => $value +1)
  ->map(fn ($value) => $value +2);

map は Collection を返す関数として定義することで、次々に関数を適用していくようなコードをスッキリ書けます。
かつ、IDE に map を補完させることもできます。

同様の機能性を提供しようとした RFC として Pipe Operator が紹介されています。

https://wiki.php.net/rfc/pipe-operator-v2

却下された提案ですが、やりたいことは stream に対する filter みたいな操作をきれいに書きたいという感じでしょうか。

これって、ruby だと mixin になるんでしょうか?英語では、Monkey Patching と呼ぶようです。
既存クラスへの機能追加が出来ると、継承を使わずに、かつ元のコードに影響を与えずに機能性を充実させることが可能です。

この提案に対するコメントとして

  • 名前空間の衝突
  • コンパイル時に不正なextensionの利用を検知できるのか?

既存クラスを変更せずに機能性を追加する方法としては、デコレーターパターンなどもありますが、今回の提案は、クラスをこじ開けて機能を追加するという感じで、とても強力な言語機能に見えます。
刺激的なアイデアですので、コメントもたくさんついています。今後の展開が注目されます

Bugs

Function to validate regular expression · Issue #9289 · php/php-src

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

正規表現のバリデーションを行う関数が無いんじゃない?というイシュー

preg_validate とかどうよ?とか、filter_var だろ?とかの話がされています。
Featureリクエストなので、RFC が出される流れになるかと思います。

正規表現には各種方言がありまして、私の知る限り現状の PHP には

  • PCRE (preg系)
  • Oniguruma (mb_ereg系)

の2系統があります。Oniguruma は https://github.com/kkos/oniguruma/blob/master/doc/RE.ja を見る限りは PCRE のパターンも入っているようです。

イシューには、mb_string の話は一切でてきてないので、十中八九は preg 系の正規表現のみが対象になることでしょう。

php bug ? addition · Issue #9286 · php/php-src

https://github.com/php/php-src/issues/9286
<?php
php -r 'ini_set("precision", 20); var_dump(17.52+69.05+13.43);'

php -r 'ini_set("precision", 20); var_dump(69.05+13.43+17.52);'

上記、計算結果が float(100) に両方ともならないのはおかしいというイシューでした。

	=> float(100)
	=> float(99.999999999999)

不動小数点計算に関するイシューです。例によって IEEE 754 をご案内して終了

GC root buffer keeps growing when destructors are present · Issue #9266 · php/php-src

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

destructor が記述されたクラスが含まれた際に、GC でメモリリークが発生しているというイシュー。
参照カウントがおかしかったようで、下記の修正コミットを見てもわかるようにカウントの計算に微修正が入っています。

https://github.com/php/php-src/commit/0709578517e4367f8b69d013f0f30c3a21624fd3

SIGPIPE while using curl · Issue #8309 · php/php-src

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

cURL が SIGPIPE を出すというイシュー。クローズされています。

AMD64(Debian Buster) で OpenSSL 1.1.1n ということで、もしかしたら同様事象に出会っている人はいそう。
問題はPHPではないということでクローズされてますので、同様事象の方はライブラリ(cURLのcライブラリ, Guzzle)か、OSのアップデートを検討すると良さそう。

Segmentation fault in mb_strimwidth() · Issue #9248 · php/php-src

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

最新の master で mb_strimwidth が segv を起こしていたというもの。

変数の初期化ミスだったようですが、mb_string って結構アクティブに手が入っているねという印象を受けました。

PHP 8.2 readonly classes allow inheriting mutable properties from traits · Issue #9285 · php/php-src

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

Readonly クラスが trait 経由で Mutable なプロパティーを継承できてしまうというイシュー

あまり良い解決策じゃないけど...という注釈付きでコミットされた修正が下記。

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

インタフェースと同様に、Readonlyクラスでtrait を使うとエラーになります。修正は未来に任せたという雰囲気がします。

ksort(..., SORT_REGULAR) behaves incorrectly on arrays with string and numeric keys since PHP 8.0 · Issue #9296 · php/php-src

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

8.0 以降で ksort の振る舞いが正しくないというイシュー

これは、8.0 以降で、文字列と数値の比較に変更が入ったにも関わらず、ksort が古いルールに従っているのが原因とのこと

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

ksort のマニュアルはこちら。key で比較して並べ替えを行います。

https://www.php.net/manual/ja/function.ksort.php

https://3v4l.org/NUN7o

8.0 以降の正しい挙動は、600が先にくるべきです。

array(2) {
  [600]=>
  int(0)
  ["aaa"]=>
  int(1)
}
int(-1)

つまり、問題の根幹はこっち

https://3v4l.org/KIMvF

修正はこのコミット

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

pecl.php.net site is down · Issue #9307 · php/php-src

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

pecl のサーバーが数時間にわたって落ちてました。
コンテナビルドで pecl install xxx とやっている場合に、ライブラリのソースコードがダウンロードできず、コンテナのビルドが止まるなどのツイートが多く見られました。

基本的には、Github で管理されているライブラリーが多いので、 Github 側のアーカイブをダウンロードして

phpize
./configure
make
make install

すれば、急場はしのげます。

is_numeric() limitation · Issue #9311 · php/php-src

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

is_numeric が Exponent 表現も true を返すのだが、チェック出来ないだろうか?というイシュー

is_numeric は文字列が数字表現であることをチェックする関数なので、質問者が要求する INT か FLOAT かというチェックには向いていません。

FILTER_VALIDATE_FLOAT FILTER_VALIDATE_INT を使って、 filter_var でチェックするのが適切だろうということで回答がついています。

Fatal error: class and trait define the same constant in the composition of child class in case constant in trait is equal to constant in child class · Issue #9272 · php/php-src

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

継承関係にあるクラスが同じコンスタント名を使って、かつ Trait 側でそのコンスタントを参照するとエラーになるというもの。

sji さんからのコメント

  • コンパイル時に未定義のクラスの定数を参照しようとしているので、エラーになるべきということ
  • self に置き換えると実行可能になるのは、ランタイムで参照されるようになるからということ

パット見は、頭が混乱してしまうコードですね。

Discussion

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