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
790
mb_trim関数を作りました
PHPカンファレンス香川の資料です #phpconkagawa
てきめん tekimen
PRO
May 11, 2024
Tweet
Share
More Decks by てきめん tekimen
See All by てきめん tekimen
PHP Internals わいわい #3 mb_*関数を作ってみよう
youkidearitai
PRO
0
51
Windows版php-srcデバッグ方法
youkidearitai
PRO
1
50
PHP Internals わいわい #1 の資料
youkidearitai
PRO
1
1.1k
PHPの次期バージョンはこの時期どうなっているのか - Internalsの開発体制について - PHPカンファレンス小田原
youkidearitai
PRO
1
680
文字とはなにか - PHPの文字コード処理について - PHP Lovers Meetup #5
youkidearitai
PRO
1
240
はじめてのOSSコントリビュート
youkidearitai
PRO
11
3.7k
文字とはなにか - PHPの文字コード処理について -
youkidearitai
PRO
0
740
現在のmbstringの立ち位置 これからどうなっていくのか
youkidearitai
PRO
0
260
PHP 8.3のmbstringの進化を見てください - コントリビューターとしてのかかわり -
youkidearitai
PRO
0
1.3k
Other Decks in Programming
See All in Programming
『GO』アプリ データ基盤のログ収集システムコスト削減
mot_techtalk
0
100
[Fin-JAWS 第38回 ~re:Invent 2024 金融re:Cap~]FaultInjectionServiceアップデート@pre:Invent2024
shintaro_fukatsu
0
400
『改訂新版 良いコード/悪いコードで学ぶ設計入門』活用方法−爆速でスキルアップする!効果的な学習アプローチ / effective-learning-of-good-code
minodriven
29
5.1k
Grafana Cloudとソラカメ
devoc
0
130
負債になりにくいCSSをデザイナとつくるには?
fsubal
9
2.1k
Flutter × Firebase Genkit で加速する生成 AI アプリ開発
coborinai
0
130
2024年のWebフロントエンドのふりかえりと2025年
sakito
1
220
ペアーズでの、Langfuseを中心とした評価ドリブンなリリースサイクルのご紹介
fukubaka0825
2
290
『GO』アプリ バックエンドサーバのコスト削減
mot_techtalk
0
120
2024年のkintone API振り返りと2025年 / kintone API look back in 2024
tasshi
0
210
定理証明プラットフォーム lapisla.net
abap34
1
1.7k
技術を根付かせる / How to make technology take root
kubode
1
230
Featured
See All Featured
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
The Cult of Friendly URLs
andyhume
78
6.2k
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
Why Our Code Smells
bkeepers
PRO
335
57k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
128
19k
We Have a Design System, Now What?
morganepeng
51
7.4k
GitHub's CSS Performance
jonrohan
1030
460k
What's in a price? How to price your products and services
michaelherold
244
12k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
7
620
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
4
400
Done Done
chrislema
182
16k
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));