Filter
Exclude
Time range
-
Near
1. types in phpdoc are in fact, less readable 2. types in phpdoc have worse (and in some cases non-existent) support for specific generic patterns 3. types in phpdoc are extremely prone to break (if you can even call it that) during refactors 4. there is no standard. none. linters, SA tools, formatters, editors support them, because they have no other choice. i can make up a random @.tag tomorrow and start using it, and there's nothing to validate it. unless of course it's used by enough people, because then it becomes "standard". exactly what happened with @.implements and @.template-implements, @.extend and @.template-extend, @.use and @.template-use, along with @.param, @.phpstan-param, @.psalm-param, @.phan-param. same prefixed nonsense with return, var, and a lot more. just 4 things that came to mind instantly
1
4
I've had this discussions for years now. No one made an argument that I couldn't counter with "well, the same is true for...". Even making PHPDoc types runtime checked would somehow be possible, surely. Not sure why we would want that, though. For me this is solely about visual separation. I want generics. Using PHPStan level 10 myself. But I want them in PHPDoc, as an official spec. Everyone would get what they want. It's a fine compromise, though. There is literally no argument for not having types in PHPDoc. That's what makes the discussion so hard. Feel free to stop taking me seriously, it's fine.
1
15
Replying to @ivan_jrmc
I can write TS for frontend but for backend nah. I'm happy with generics via phpdoc and phpstan
1
204
$relations would be ‘receipt’ or ‘statement’, an array of Payment relationships to later load
7
I'm not sure I understand. Wouldn't be more clear to use directly: @param array<int, Payment> $relations
1
17
Smart approach, thanks for sharing 👌
3
🚀 開発環境が更新されました。以下のPRがマージされました。#オプチャグラフ #502: [STG] perf: ルーム統計グラフのローソク足表示で不要なデータ取得をなくす(DBアクセス削減・取得データ軽量化) --- ルーム個別ページのグラフを「ローソク足」で表示するとき、描画に使わない日次メンバー数を毎回取得し、さらにレスポンスに同じ日付配列が二重に乗っていた。これを整理し、ローソク足は OHLC のデータだけを取得・返すようにした。 ## これまでの問題 - ローソク足でも日次メンバー数(member)を取得していた。ローソク足では描画に使わないのに、表示のたび統計DBへアクセスしていた。 - レスポンスに日次の日付 `date` と OHLC 用の日付 `ohlcDate` が両方乗り、中身が同じで二重だった(指摘いただいた点)。 ## 対処 - ローソク足は OHLC 専用の日付軸 `ohlcDate` だけで描くようにし、`date` / `member` を取得も返却もしない。 - API(`app/Services/Chart/OpenChatChartApiService.php`): ローソク足や OHLC だけの取得要求では統計テーブルを引かず、`ohlcDate` `memberOhlc`(順位ONなら `positionOhlc`)だけ返す。 - フロント(`frontend/oc-app/src/graph/util/fetchRenderer.ts`): ローソク足は member 層を取得しない(順位ONでも `positionOhlc` だけ取得)。折れ線へ切り替えたとき初めて member を遅延取得する。 - 期間タブ(週/月/全期間)の本数判定も OHLC 本数で行うよう揃えた。 - `frontend/oc-app/README.md`(表示状態ごとのAPIとデータ型)も更新。 差分は純減(9ファイル・ 160/-205)で、ローソク足まわりのコードがシンプルになった。 ## 確認 - PHPStan / 該当 PHPUnit(OpenChatChartApiServiceTest 10件)/ tsc 通過。 - 折れ線・ローソク足 × ランキング・急上昇・なし × 期間タブの全ビュー、およびモード切替・順位ON/OFF・期間切替の操作をヘッドレスで確認(JSエラーなし・順位オーバーレイ整合・折れ線への切替で member が遅延取得され正しく描画)。 --- 🤖 Generated with Claude Code (claude-opus-4-8[1m]) Posted from: `user-B550M-Pro4:~/repos/Open-Chat-Graph`
1
73
that service is actually only for float comparison, so the service has gt, gte, lt, lte… etc comparison methods with default delta so we never compare floats again unsecurely. It’s too late to ban floats completely in this codebase…
1
1
11
🚀 開発環境が更新されました。以下のPRがマージされました。#オプチャグラフ #496: [STG] perf: ルーム統計グラフの初回表示を軽量化し、アクセス集中時のDB競合を低減(タブ判定の事前計算+表示期間だけ取得) --- ## 何が変わるか ルーム個別ページ(/oc/{id})のグラフ初回表示で、サーバが叩くDBを大きく減らす。特に Googlebot 等のクロール集中時に出ていた `database is locked` 系のDB競合を緩和する。 ## これまでの問題 グラフ初回表示で2つの重い読み取りが毎回走っていた。 1. タブ/ボタン出し分け判定(可用性メタ)のために、表示のたびに4つのDB(統計・ローソク足・順位の各SQLiteと毎時データのMariaDB)へCOUNT。 2. 系列データを、表示は週/月/全をクライアントで切り出すだけなのに、初回に全期間ぶん取得。 アクセス集中時、statistics 等のSQLite読みが競合し `database is locked`(本番エラー: [TH] Googlebot, span=hour・meta=1 の初回ロードで `getDailyMemberStatsDateAsc` が locked)の一因になっていた。 ## 対処 1. 可用性メタを cron で事前計算し MySQL の `oc_page_cache.chart_meta` に持たせ、/oc 表示の既存1クエリで読みHTMLに埋め込む。初回の meta=1 リクエストを撃たない。 2. 系列は表示中の期間タブの窓だけ取得し、拡大時は足りない古い側の差分だけ取得(窓は最新日終端固定なので連続1範囲)。一度取得した範囲は再取得しない。 3. 系列を層(member / position / memberOhlc / positionOhlc)に分け、`?series=` で必要な層×不足範囲だけ取得(全期間で人数表示中に順位ONしても人数は再取得しない)。 4. 事前計算の毎時順位は実行ごとに1回の一括GROUP BY(バックフィルでも MySQL gone away を起こさない)。 5. 取得が一過性の5xx(リトライ後も不可)・403等で最終失敗したら、壊れた表示でなく再読み込みを促すエラー表示。5xx は fetcher が1回だけ自動リトライ。 ## アーキテクチャ(データの流れ) フロント → API: - 初回: /oc ページHTMLに埋め込んだ可用性メタ `#chart-meta` を `fetchRenderer.ts`(readEmbeddedChartMeta) が読む。埋め込みがあれば初回 meta=1 を撃たない(`App.tsx` init → `fetchChartData`)。 - 系列取得: `fetchRenderer.ts` が層別に `GET /oc/{id}/chart?series=<member,position,…>&sort&scope&category&mode&from&to` を叩く。各層を date→値でキャッシュし、必要層の足りない古い範囲だけ・同範囲の層はまとめて1リクエスト。`fetcher.ts` が URLキャッシュ+5xx 1回リトライ。操作時は `chartState.ts`(handleChangeLimit / handleChangeRankingRising / handleChangeChartMode / handleChangeCategory) → fetchChart。 API 処理: - ルート `oc/{open_chat_id}/chart` → `OpenChatChartApiController::chart` → `OpenChatChartApiService::buildChartResponse`。 - `series` 指定で層だけ返す/`from`・`to` で範囲化/`meta=1` でメタ同梱(埋め込み無し室のフォールバック)/`span=hour` は最新24時間。 - 系列の組み立て: 人数=`StatisticsChartArrayService::buildStatisticsChartArray`、順位=`RankingPositionChartArrayService::getRankingPositionChartArray`、ローソク足=`buildCandlestickSeries`、最新24時間=`buildHourSeries`。 リポジトリ: - 人数: `SqliteStatisticsPageRepository::getDailyMemberStatsDateAsc`(statistics SQLite・`date BETWEEN`)/日付範囲 `getMemberDateRange`。 - 順位: `SqliteRankingPositionPageRepository::getDailyPosition`(ranking_position SQLite)。 - ローソク足: `SqliteStatisticsOhlcRepository` / `SqliteRankingPositionOhlcRepository`(`getOhlcDateAsc`)。 - 最新24時間・メタのhour集計: `RankingPositionHourRepository`(MariaDB。1室 `getHourPositionCounts` / 一括 `getHourPositionCountsAll`)。 - メタの読み(primary): `OpenChatPageRepository::getOpenChatByIdWithTag` が `oc_page_cache` を LEFT JOIN(narrative と chart_meta を1クエリ)。`OpenChatPageController` が `#chart-meta` へ埋め込む。 cron でのキャッシュ更新(条件は下表): - `oc_page_cache.chart_meta` は `OcPageCacheGenerator::generateForIds`(per-room) が `ChartMeta\ChartMetaBuilder::build` で生成し `OcPageCacheRepository::upsertMany` で保存。毎時順位は `UpdateOcPageCacheService::handle` がチャンクループの外で一括 `getHourPositionCountsAll` を1回だけ取得して渡す(per-room MariaDB を撃たず gone away 回避)。 - 起動は `SyncOpenChat::hourlyTask`(毎時) / `dailyTask`(日次) / genetop(全件)。 フォールバック(埋め込みが無い室): - `#chart-meta` が null → フロントは meta=1 を撃つ → `OpenChatChartApiService` が `ChartMetaBuilder::build`(hourEntry 無し=ライブ・per-room で hour 取得)でメタを作る。primary(cron) と同一コードなので結果は一致する。 - メタ計算は `app/Services/Statistics/ChartMeta/ChartMetaBuilder.php` の1箇所のみ。`StatisticsChartArrayService` は「メンバー系列生成専用」。 ## oc_page_cache の生成タイミング(マッピング) chart_meta は分析文(narrative)と同じ `oc_page_cache` 行に同梱され、同じ再生成経路で作られる。件数は ja(本番同等ローカル)実測。 | タイミング | 起動 | 対象の室(条件) | 件数(ja実測) | |---|---|---|---| | 毎時 | `SyncOpenChat::hourlyTask`(毎時30分) | 直近1時間で人数が変わった室 + 新規ランク入り | 約 4,320 | | 日次 | `dailyTask`(23:30) | `getForDaily` = 変動(過去8日) + 新規(レコード8件未満) + 週次更新(最終記録が1週間以上前)。ランキング外の室も週次更新で拾い、最長でも約1週間で全室が一巡 | 約 108,274 | | genetop(全件) | 管理画面 | `getOpenChatIdAll` = 全室。毎時順位は一括化済みで全件でも gone away しない(ただし時間はかかる) | 約 242,386 | | バックフィル / write-through | 管理画面 / idCsv 指定 | 指定した室のみ | 指定数 | ## 未生成室(chart_meta が無い室)の挙動 - 新規室、または初回バックフィル前の室は chart_meta が無い → ページ埋め込みが null → フロントは meta=1 でライブ計算(ChartMetaBuilder)にフォールバックする。 - このときの系列は全期間取得になり、窓・差分の最適化は効かない。ただし表示は壊れない(従来どおり=無劣化)。 ## フォールバックを外せない理由 - 新規室が常時発生し、次の再生成まで chart_meta を持たないため、ライブ計算経路は恒久的に必要。 - ただしリファクタで「二重実装」は解消済み。フォールバックは同じ `ChartMetaBuilder` のライブ実行であって、余計なコードではない。 ## 主な変更箇所 - 事前計算: `Statistics/ChartMeta/ChartMetaBuilder`・`Statistics/ChartMeta/ChartAvailabilityCalculator`(しきい値の単一定義)・`OcPageCacheGenerator`(毎時順位は一括 `getHourPositionCountsAll`)・`UpdateOcPageCacheService`。 - 同梱: `OpenChatPageController` / `Views/oc_content.php` / `OpenChatPageRepository`(chart_meta をJOINで読む)。 - API: `OpenChatChartApiController` / `OpenChatChartApiService`(from/to 範囲+`series` 層)と各系列リポジトリ(`date BETWEEN`)。 - フロント: `frontend/oc-app`(層別の最小差分取得、取得失敗時のエラー表示、5xx 1回リトライ)。 - genetop: 全室の `oc_page_cache` 再生成を追加。 - CLAUDE.md: 毎時/日次にキャッシュ生成を足したら genetop で全件再生成できるようにするルールを明記。 ## デプロイ・運用 - `oc_page_cache` に `chart_meta` 列を追加(デプロイ時 `sync_mysql_schema` が自動反映、手動DDL不要)。CI/mock も `setup/init-database.sh` が schema から構築するので列は在る(NULL時はフォールバックで /oc は200)。`deploy.yml` 変更不要。 - 反映後に genetop を1回実行すると全室の chart_meta が揃い、全室が窓・差分の最適化経路に乗る。実行しなくても毎時/日次で順次埋まり(最長約1週間)、未生成室はそれまでフォールバックで無劣化。 ## 確認 - 埋め込みメタ == meta=1 ライブ計算 が実データ複数室で一致(同一 ChartMetaBuilder)。 - `series` 未指定の全レスポンス行列が改修前とバイト一致(後方互換)。`series` 各層は該当層のみ返し、範囲も有効。順位ON時は `series=position` 1本のみで人数を再取得しないことをNetworkで実証。 - 窓→拡大が差分のみ・再取得なし・繋ぎ目で連続描画、ローソク足のタブ維持、新規室のフォールバック、最新24時間をヘッドレスで確認。 - PHPStan / PHPUnit(新規テスト含む)green。 --- 🤖 Generated with Claude Code (claude-opus-4-8[1m]) Posted from: `user-B550M-Pro4:~/repos/Open-Chat-Graph` ## 追記: レスポンスのさらなる軽量化(2コミット) 層別取得のデータ形をさらに削った。 - ローソク足の日付を1本に集約: OHLCの各要素が持っていた `date` をやめ、OHLC専用の日付軸 `ohlcDate` を1本だけ返す。`memberOhlc`/`positionOhlc` はこの軸とindex整合の「値だけ」の配列にした(人数と順位の両方を表示すると日付配列が3本になっていたのを1本に。`positionOhlc` の `null` はその日が圏外)。 - 順位の時刻配列を急上昇のみに: 時刻ラベル `time` は終日時刻を持つ急上昇でだけ返し、ランキング・人数のみ・最新24時間・ローソク足では配列ごと返さない(フロントは「無ければ時刻表示なし」として扱う)。 - `frontend/oc-app/README.md` を追加し、表示状態ごとに送るAPIと返るデータ型を明記。 検証: PHPStan / 該当 PHPUnit(OpenChatChartApiServiceTest 10件)/ tsc 通過。折れ線・ローソク足 × ランキング・急上昇・なし × 期間タブの全ビューをヘッドレスで描画確認(JSエラーなし・順位オーバーレイ整合・tooltipが人数OHLCと順位OHLCの両方を表示)。 --- 🤖 Generated with Claude Code (claude-opus-4-8[1m]) Posted from: `user-B550M-Pro4:~/repos/Open-Chat-Graph`
2
377
/** * @param array<int,string> $relations {@relations-of Payment} * */ It verifies that the $relations argument passed to the function contains only valid Payment (model) relationships for later use with the with() method in the query.
1
34
Thanks for sharing. All great additions, we use implicitly. I'll steal some of them :) What does the last one include? Operation between float and float? E.g. 0.5 * 0.8 would throw an error?
1
23
Tomas Votruba retweeted
Using an agent... ....what custom @rectorphp rule or @phpstan extension/rule have you created, that you would not have the nerves and the time to create manually?
5
2
3
1,081
prevent returning assoc in public/protected methods, only list<something>. Prevent numeric string array keys. Prevent direct datetime construction and use dedicated service instead (for timezone problems). Forbid using some classes. Prevent direct float comp, and use service.
1
1
29
🚀 開発環境が更新されました。以下のPRがマージされました。#オプチャグラフ #480: [STG] perf: コメント一覧の取得を高速化(いいね集計を表示分だけに限定し約15%短縮) --- ## 問題 オープンチャットのコメント一覧を開くたびに走る「コメント取得処理」が、コメントへのいいね集計を毎回 `like` テーブル全体から求める作りになっていた。MariaDB の最適化(split optimization)で全件走査自体は回避されていたものの、集計用の派生テーブルを毎回組み立てるコストが残っていた。 ## 対処 そのページに表示するコメントだけにいいね集計を限定する方式に変えた。コメント画像の取得が既に使っている「表示分だけまとめて取得(IN集計)」と同じパターン。 - まずコメント取得処理(`CommentListRepository::findComments()`)でページぶんのコメントを確定(comment log のみ、index駆動で軽い) - その `comment_id` ぶんだけ `like` を集計してマージ(`fetchLikeCounts()`) リポジトリのインターフェースもコントローラも変えていない。 ## 効果 ローカル実測(現実的なフルページ・OLDとSPLITを交互に2000サンプル×3回計測)でコメント取得処理が約15%短縮(中央値 1.12ms → 0.94ms、差0.18ms > 標準偏差0.12ms で再現)。 DB の最適化任せでなく明示的に表示分へスコープするため、`like` が大きい本番ほど効果は同等以上を見込む(本番未計測のため数値はローカル基準)。 ## 検証 - 旧クエリ(全件集計)と結果が完全一致(複数部屋・ページ・voted 含めミスマッチ0) - phpunit OK(`CommentListRepositoryTest`。古い DTO コンストラクタ呼び出しも現行4引数に修正) - PHPStan OK(変更3ファイル No errors) --- 🤖 Generated with Claude Code (claude-opus-4-8[1m]) Posted from: `user-B550M-Pro4:~/repos/Open-Chat-Graph`
67
🚀 開発環境が更新されました。以下のPRがマージされました。#オプチャグラフ #468: [STG] refactor: ルーム分析文キャッシュをMySQLへ統合し /oc を1クエリ化、間欠ストールの原因だったSQLiteを全廃 --- ## 何をするか ルーム個別ページの「分析文」事前計算キャッシュを SQLite から MySQL(ocgraph_ocreview*)へ移行し、 `/oc` 表示を1 MySQLクエリで完結させる。あわせて間欠ストールの原因だった SQLite を全廃する。 ## 背景 これまで `/oc` は MySQL(ルーム情報)+SQLite(分析文)の2系統を読んでおり、SQLite の WAL 競合で 本番が間欠的に固まる問題があった(2026-06-12 障害, PR #439/#440)。分析文は部屋ごとの小さなJSONで 容量も小さいため、MySQL にテーブルを足して `getOpenChatByIdWithTag` の JOIN で一緒に取れば、 SQLite と回避策を丸ごと無くせる。 ## 変更内容 - MySQLテーブル `oc_page_cache` を ja/tw/th の ocreview schema に追加(`narrative_data` mediumtext) - `getOpenChatByIdWithTag` に `LEFT JOIN oc_page_cache` `narrative_data` を追加 → 分析文も1クエリ取得 - Controller は `$oc['narrative_data']` から分析文を組み立て(SQLite read 廃止) - `OcPageCacheRepositoryInterface` を新設し MySQL 実装を DI バインド。読みは JOIN に寄せ書き込み専用に。 旧 SQLite 実装(SQLiteOcPageCache・repo・sqlite schema)を削除 - FileStorage設定・prod-sync同期対象・setupスクリプトから SQLite版 oc_page_cache を一掃 - 「分析文/関連ルーム」誤記を「分析文」に修正(関連ルームはこのキャッシュに含まれない) - Repository は必ず Interface とセットで作る方針を CLAUDE.md に追記 ## デプロイ後の手順(重要) デプロイで schema-sync が各 ocreview DB に `oc_page_cache` を追加する(add-only・安全)。 テーブルは初期空のため、デプロイ後に各言語でバックフィルが必要: `php batch/exec/update_oc_page_cache.php '' / '/tw' / '/th'`(または admin GUI)。 バックフィル前は分析文が空表示になるだけでエラーやダウンタイムは無い。 ## 検証(ローカル・全項目パス) - PHPStan エラー0 / PHP構文OK - schema-sync で3DBに oc_page_cache を作成、5件バックフィル成功(updated_at=毎時クロール完了時刻) - `/oc/21`・`/oc/228516` が 200・分析文セクション描画・例外/データ漏れなし - キャッシュ未生成ルームも 200・空表示・500なし --- 🤖 Generated with Claude Code (claude-opus-4-8[1m]) Posted from: `user-B550M-Pro4:~/repos/Open-Chat-Graph`
327
Shipped a ton of rector rules using agents, every single one in this package as well as github.com/SanderMuller/lara… (and both repos have phpstan counterparts too). Did create some phpstan rules by hand pre-AI, though
1
22
👍 Looks good. Just this one?
1
50
I am working on a PHP to Zephir transpiler. The project is using PHPStan rules to check if the PHP code can be transpiled. The Rector rules change the PHP code to make it transpilable. I would have never get the time to do this without a coding agent.
43