Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
mb_trim関数を作りました
Search
てきめん tekimen
PRO
May 11, 2024
Programming
1
540
mb_trim関数を作りました
PHPカンファレンス香川の資料です #phpconkagawa
てきめん tekimen
PRO
May 11, 2024
Tweet
Share
More Decks by てきめん tekimen
See All by てきめん tekimen
Windows版php-srcデバッグ方法
youkidearitai
PRO
1
37
PHP Internals わいわい #1 の資料
youkidearitai
PRO
1
830
PHPの次期バージョンはこの時期どうなっているのか - Internalsの開発体制について - PHPカンファレンス小田原
youkidearitai
PRO
1
410
文字とはなにか - PHPの文字コード処理について - PHP Lovers Meetup #5
youkidearitai
PRO
1
180
はじめてのOSSコントリビュート
youkidearitai
PRO
11
3.3k
文字とはなにか - PHPの文字コード処理について -
youkidearitai
PRO
0
570
現在のmbstringの立ち位置 これからどうなっていくのか
youkidearitai
PRO
0
180
PHP 8.3のmbstringの進化を見てください - コントリビューターとしてのかかわり -
youkidearitai
PRO
0
1.1k
PHP 8.2と8.1で取り込まれたプルリクエストについて
youkidearitai
PRO
0
290
Other Decks in Programming
See All in Programming
null or undefined
susisu
20
4k
Meet BrowserEngineKit
swiftty
0
190
フロントエンドカンファレンス北海道2024 『小規模サイトでも使えるVite 〜HTMLコーディングをよりスマートに〜』長谷川広武(ハム)
h2ham
1
2.5k
健康第一!MetricKitで始めるアプリの健康診断 / App Health Checkups Starting with MetricKit
nekowen
4
790
iOSDC 2024 SMBファイル共有をSwiftで実装する
kishikawakatsumi
1
110
メモリ最適化を究める!iOSアプリ開発における5つの重要なポイント
yhirakawa333
0
370
Boost Your Performance and Developer Productivity with Jakarta EE 11
ivargrimstad
1
930
初めてのiOS関連GitHub ActionsをMarketplaceに公開するまでの実録
konifar
3
200
Some more adventure of Happy Eyeballs
coe401_
2
150
RAGの回答精度評価用のQAデータセットを生成AIに作らせた話
kurahara
0
210
Polars を Kaggle コンペで使ってみた(LMSYS Chatbot Arena)
kohecchi
1
360
Desafios e Lições Aprendidas na Migração de Monólitos para Microsserviços em Java
jessilyneh
2
130
Featured
See All Featured
How GitHub Uses GitHub to Build GitHub
holman
472
290k
Music & Morning Musume
bryan
46
6k
Keith and Marios Guide to Fast Websites
keithpitt
408
22k
Typedesign – Prime Four
hannesfritz
38
2.3k
Pencils Down: Stop Designing & Start Developing
hursman
118
11k
How to Think Like a Performance Engineer
csswizardry
15
910
The Illustrated Children's Guide to Kubernetes
chrisshort
46
48k
What's new in Ruby 2.0
geeforr
340
31k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
22
1.7k
Rails Girls Zürich Keynote
gr2m
93
13k
What's in a price? How to price your products and services
michaelherold
241
11k
Into the Great Unknown - MozCon
thekraken
28
1.4k
Transcript
mb_trimを作りました
自己紹介 てきめん • https://tekitoh-memdhoi.info • X: @youkidearitai • https://github.com/youkideari tai
• PHP 8.4で複数の関数を作った – mb_trim – mb_ucfirst、mb_lcfirst – grapheme_str_split オレ
遡ること2022年 • とあるFeature request(機 能追加のリクエスト)が来る • それがマルチバイト対応の trim関数を作ってくれない かというもの •
しかし、実装してくれる人が 現れず…
そのときのてきめんの状況 • 2022年8月はまだ8.1でmbstringが変わると認識 してなかった • 2022年12月からmbstringのレビュー作業に加 わった • mb_trimのfeature requestは認識してた
時は流れ • 2023年9月、ぼくがこの Feature requestを拾う – このころのぼく は、mbstringのレビュー も一通り落ち着いて余力 があったことが大きな要
因
実装するしかない! • もう自分でRFC書いた ほうがいいよと言われる • 皆もmake sense(理に かなってる)と言ってる 以上、もうしない理由が なかった
RFCの草案をもらう • 8ctopusさんが草案を書い てくれてた • こちらを参考に、ちょっと修 正 – mb_ltrimとmb_rtrimを追 加
– $encodingを追加
PHP Internalsへ投稿 • 8ctopusさんが internalsメーリングリ ストへメールを送れな かったことから、代理で 「ぼくもほしいのでどう 思う?」と送ってみた
PoCの作成 • 概念実証コードを作成 し、プルリクエストにしま した – この時点では、Draft pull requestとしました
RFCを記述するWiki Karma Request • RFCを記述するのが初めてだったので、まずアカウントを作り ます • アカウントを作ったら、Internalsメーリングリストへ「RFC Karma Request」を投げます
– タイトルはこのままで「〇〇したいです」を添えれば大体許可さ れます – 許可されたらWikiの編集権をもらえます
RFCの作成 • RFCを作成していきます • Wikiなので、空いてるURLに記述できます – 今回は https://wiki.php.net/rfc/mb_trim としました •
先程の中身を記述していきます
RFCの考慮 • RFCは他人にわかるようにいろいろなことを考えま す • 一番考えたのは$encodingの部分でした – trim関数には「..」という、範囲を指定する表記法がある のですが、これを実現するのは不可能に思いました •
というのも、文字コードごとに範囲が違いますし、Unicodeが 広すぎるのも問題です
RFCをInternalsメーリングリストへ送信 • メーリングリストへ送信して、議論します • この状態になったら、RFCを「Under Discussion」 にします – Under Discussionを少なくとも2週間続けます
• ただ、議論のすべてに答えることが必要でその合意形成に1 年とか経ったりするものもたくさんあったりします
Votingに入る • 投票フェーズに入ります • 期間は2週間+αを置きます • ここで2/3のYesを貰えれば可決(Accepted)となり ます • mb_trimはここで可決をもらいました
そして実装へ • 先程のプルリクエストを普通のプルリクエストにし ます • レビューを受けます – ここが結構おもしろかった
めっちゃアツいレビュー • 主にnielsdosさ ん、alexdowadさんか らレビューを受ける
128コードポイント以上の対応 • $stringが128コードポ イント以上の処理に対 応してないよとレビュー を受ける – そういえばそうだった
解決策が思い浮かばない、寝る • 色々と試行錯誤してた けどむずくて無理!JST だともう寝る時間だ寝 るってなっててnielsdos さんに教えを請うすが た – 似たような実装で解決
コードポイントって何 • Unicodeにおけるコードポイントとは、U+xxxxの xxxxの部分で、0x0から0x10FFFFの16進数が入る – https://www.unicode.org/glossary/#code_point – 何らかの文字がここに割り当てられるのでこれを1文字 として数える事が多い
線形探索以外になんかあるの!? • $charactersを1コードポイ ントずつ線形(O(N))に探索 してたらここはHashTable を使えばいいよと教えを請 う – 最初、どういうこと?ってなっ てnielsdosさんに聞いてる
ぼく
HashTableでO(1)にする • HashTableのキー部分に コードポイントをあてがうと いうテクニック(値はなん でもいい)でO(1)にすると いうテクニックを教えても らった – すげえ!ってなった
ハッシュテーブル(HashTable)ってなに • キーにハッシュ関数を与えてあげて、一意 のアドレスに値を格納・取り出すデータ構 造 – ハッシュ関数というくらいですから、md5と かsha1とかでもいいのです • 衝突を気にしなければO(1)で済ませられ
る – 衝突が絡むとO(N)になったりするけど今 回は衝突を考える必要はなかった • php-src では HashTable という構造体 が用意されている
さっきから言ってるO(N)とかってなに • 計算量、オーダーのこと • O(N)はN個あったら最悪N回計算し ないといけないことを示す – 0個では0回 – 線形探索がこれ
• O(1)は何個あっても1回で済む – 0個でも1回だけど – ハッシュテーブルはこっち
XORによるビット演算のテクニック • 左側のtrimが終わった らフラグをfalseにして たけど、mode自体を XORすればフラグ消せ るよと教えられる – すげー!ってなりました
ついにapprovedをもらう • nielsdosさんによるapproved をもらう – すごくお世話になりましたマジで ありがとうございます • alexdowadさんに「squashし てもらっていい?」ということで
git rebase -i とgit push – forceする – php-srcではsquashでひとまと めにしてます
Landed on master • NEWSの追 加、UPGRADINGの追 加などをしてマージと いうかsquash commitされました
Optimizations for mb_trim #12803 • nielsdosさんがmb_trim 関数のパフォーマンス調 整をしてくれて、 4文字 (コードポイント)までは線
形探索したほうが速いとわ かった – O(1)が0個でも1回計算し なきゃならないところもあり うる
Build failed at mbstring_arginfo.h on Windows(Visual C++) #13789 • Windowsの日本語のVisual
C++でビルドができないという 問題を(あの)廣川さんから メールでもらう – $charactersをUTF-8バイト列 でコンパイルしていたのが問 題 – コンパイル時のフラグにUTF- 8であることを加えることで対 処
mb_trim() inaccurate $characters default value #13815 • mb_trim関数群で文字コードが UTF-8じゃないときにtrimしない というIssue
– inaccurateが「正しくない」なの で、最初なんのことかわからな かった… – 結局、$charactersを決め打ちし てるのがよくないので、NULLが 正しいのでは?となる
Fix GH-13815: mb_trim() inaccurate $characters default value #13820 • nielsdosさんによるプルリク
エスト – $charactersをNULLにしま しょうというプルリクエスト – ただし、RFCの内容を書き換 えるためPHP Internalsで議 論する必要になり議論を行っ た
mb_trimのデフォルト値変えてもいい? • PHP Internalsメーリングリストで、mb_trimのデフォルト 値を変えてもいいかと質問してみる • 変えるしかないならそれでいいのではという意見 • RFCは必要ないとの意見をもらう •
ぼくは色々ごちゃごちゃ動いてた – mb_trimのRFC書き換えて怒られた(?)り、戻したり
結果として書き換わりました • $charactersはデフォルト値NULLとなり、NULLのとき にRFCで決まっていたコードポイントを削除するように なりました • mb_trim($str, encoding: “Shift_JIS”); などのときに
正しく削除できるようになりました • こういう設計ミスがあったときに参考にしてもらえれば
使い方 • mb_[lr]?trim関数はいわゆる全角スペース(U+3000)もtrimできます – PCREで言うところの\sなどをサポートしています • ユースケースの一つとして、mb_ltrim関数を使ってUTF-8 BOMを削除できます – mb_ltrim($str,
“\u{FEFF}”); • 例えばmb_substrでZero Width Joiner(ZWJ)を含む絵文字などでZWJが残ったと き、mb_rtrim関数を使ってZWJを削除できます – mb_substr(mb_rtrim(“ ”, “\u{200D}”), 0, 2); 🙇♂️ • 複数の文字(コードポイント)にも対応してます – mb_trim($str, “ \n\r\u{200D}\u{FEFF}”); • もちろん、他の文字エンコーディングにも対応しています – mb_trim($str, encoding: “shift_JIS”); • マニュアルはPHP 8.4に合わせて書き出すと思います
まとめ • mb_trim、mb_ltrim、mb_rtrim関数を作りました – どんなタイミングで作ったのかを説明しました • PHP Internalsとのコミュニケーションについて説明しまし た •
レビューを経てめちゃくちゃすごく勉強になりました • PHP 8.4で入るこれらの関数をお楽しみに
Appendix: mb_trimのアルゴリズム • 1コードポイントごとに左から右へ処理をしていく • 128コードポイントごとにto_wcharメソッドが呼び出される • 左側にtrimする文字があればleftを1足す • 左側のtrimする文字がなければ右側のtrimに移るため、フラグを
rightへの処理にするため、XORでMB_RTRIMに変更 • 右側にtrimする文字があればrightを1足す • 右側にtrimする文字がなければrightを0にリセット • 下記のような擬似コードでmb_substrする: – mb_substr($str, left, mb_strlen($str) – (right + left));