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
550
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
41
PHP Internals わいわい #1 の資料
youkidearitai
PRO
1
860
PHPの次期バージョンはこの時期どうなっているのか - Internalsの開発体制について - PHPカンファレンス小田原
youkidearitai
PRO
1
420
文字とはなにか - PHPの文字コード処理について - PHP Lovers Meetup #5
youkidearitai
PRO
1
190
はじめてのOSSコントリビュート
youkidearitai
PRO
11
3.3k
文字とはなにか - PHPの文字コード処理について -
youkidearitai
PRO
0
580
現在のmbstringの立ち位置 これからどうなっていくのか
youkidearitai
PRO
0
190
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
Swiftコードバトル必勝法
toshi0383
0
170
事業フェーズの変化に対応する 開発生産性向上のゼロイチ
masaygggg
0
220
Android開発以外のAndroid開発経験の活かしどころ
konifar
2
1.1k
Findy - エンジニア向け会社紹介 / Findy Letter for Engineers
findyinc
4
90k
rails_girls_is_my_gate_to_join_the_ruby_commuinty
maimux2x
0
200
あなたのアプリ、ログはでてますか?あるいはログをだしてますか? (Funabashi.dev用 軽量版)
uzulla
2
130
Boost Performance and Developer Productivity with Jakarta EE 11
ivargrimstad
0
560
Rechartsで楽にゴリゴリにカスタマイズする!
10tera
1
170
GraphQLとGigaViewer for Apps
numeroanddev
2
190
REXML改善のその後
naitoh
0
190
ECMAScript、Web標準の型はどう管理されているか / How ECMAScript and Web standards types are maintained
petamoriken
3
390
私のEbitengineの第一歩
qt_luigi
0
450
Featured
See All Featured
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
26
3.9k
Being A Developer After 40
akosma
84
590k
How to train your dragon (web standard)
notwaldorf
85
5.6k
Building an army of robots
kneath
302
42k
Reflections from 52 weeks, 52 projects
jeffersonlam
346
20k
It's Worth the Effort
3n
182
27k
Speed Design
sergeychernyshev
22
440
Pencils Down: Stop Designing & Start Developing
hursman
119
11k
Six Lessons from altMBA
skipperchong
26
3.4k
The Power of CSS Pseudo Elements
geoffreycrofte
71
5.3k
Making the Leap to Tech Lead
cromwellryan
128
8.8k
Code Reviewing Like a Champion
maltzj
517
39k
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));