Slide 1

Slide 1 text

PHP Internals わいわい mb_*関数を作ってみよう!

Slide 2

Slide 2 text

自己紹介 てきめん ● https://tekitoh-memdhoi.info ● X: @youkidearitai ● https://github.com/youkidearitai ● PHP 8.4で複数の関数を作りました – mb_trim, mb_ltrim, mb_rtrim – mb_ucfirst, mb_lcfirst – grapheme_str_split オレ

Slide 3

Slide 3 text

アジェンダ ● まずはPHPをコンパイル! ● mbstring拡張について内部構造の解説 ● mb_*関数の検討 ● 作成 ● テスト

Slide 4

Slide 4 text

趣旨 ● PHP Internals Bookを元に、PHPのソースコード、php-srcを 取得、コンパイルしたりソースコードを読みます – https://www.phpinternalsbook.com/ – あわよくばバグを見つけたら報告したり – あわよくばテストコードを修正したり – 更に行けば関数・機能を追加するとか ● PHP Internalに向かって新機能を追加する提案をしたりで きないかと思っています

Slide 5

Slide 5 text

コンパイルの前段階 ● Linuxを用意します ● 今回はDockerを使います – WSLやmultipass、limaなどを使ってもらっても構いま せん

Slide 6

Slide 6 text

PHPのコンパイルの準備 > docker pull ubuntu:22.04 > docker run -it ubuntu:22.04 bash # apt update && apt install -y pkg-config build- essential autoconf bison re2c libxml2-dev libsqlite3-dev gdb git libonig-dev # cd ~ # /root # git clone https://github.com/php/php-src

Slide 7

Slide 7 text

PHPのコンパイルの準備 # cd php-src # ./buildconf -f # ./configure --enable-debug --enable-mbstring # make # make test # make install # --prefix を指定していないので/usr/local/に入る # php -v #これで実行できる!

Slide 8

Slide 8 text

この状態を保存します ● Command + p + qで抜けるか、もしくは別のコンソー ルを開いてください ● > docker ps で開いているContainer IDを調べます ● > docker commit [container id] ubuntu:php85 – このようにすればubuntu:php85で今までの作業した内容 を保存して、コンパイルできた状態で入れます

Slide 9

Slide 9 text

このようにコンテナを作れました > docker run -it ubuntu:php85 root@ea6b72b5f128:/# php -v PHP 8.4.0-dev (cli) (built: May 31 2024 00:57:46) (NTS DEBUG) Copyright (c) The PHP Group Zend Engine v4.4.0-dev, Copyright (c) Zend Technologies

Slide 10

Slide 10 text

tips ● 今回はDockerを使いましたが、LinuxやmacOS内 部で複数のPHPを持ちたいときは --prefix オプ ションが便利です。 – --prefix=$HOME/php84 とかしてあげると、ホームディ レクトリ配下にバージョンごとにコンパイル・インストー ルができるわけです。

Slide 11

Slide 11 text

デバッグ手法 ● Linuxではgdbとかlldbなどが使えますが、今回はgdb を使います ● コンテナ内部でvimとctagsなどを利用してソースコー ドを読みます – 手元でコンパイルできるとVisual Studio Codeがつかえた りするようですね ● https://php.github.io/php-src/introduction/ides/visual-studi o-code.html – このあたり知ってる人は共有してくれると嬉しい

Slide 12

Slide 12 text

開発環境を揃える # apt install exuberant-ctags vim # cd ~/php-src # ctags -R . # カレントディレクトリが/root/php-src

Slide 13

Slide 13 text

コンパイルオプションあれこれ 変数 CC をつけるとコンパイラを指定できます 変数 CFLAGS でコンパイルオプションを指定できま す 例: CC=clang CFLAGS=”-g” ./configure –enable- debug # clangでコンパイルし、-gオプションを加え られます

Slide 14

Slide 14 text

テストについて https://www.phpinternalsbook.com/tests/runni ng_the_test_suite.html # sapi/cli/php run-tests.php # すべてのテストを行 う # sapi/cli/php run-tests.php -P ext/mbstring # mbstring拡張のみテストする

Slide 15

Slide 15 text

いざmbstring関数の実装へ ● これで準備はおわりました ● mbstring関数の実装をしていきましょう – mb_my_function関数を作ります ● 仕様として、「最初の1文字を取り除いてEUC-JPに変換する」 としましょう

Slide 16

Slide 16 text

どうしてmbstringか ● CJK(China, Japan, Korea)ユーザーはこの拡張に とてもお世話になります ● 母国語を日本語とする我々はPHPのアドバンテー ジがここにあります ● mbstringへのコントリビュートがPHPへのコントリ ビュートの近道だと考えています

Slide 17

Slide 17 text

関数の作成 ● 今回のゴールは関数の作成です ● まずは関数の作り方を学びます ● mbstringで関数を作るので、ext/mbstringに作業 します。ただし、カレントディレクトリはphp-srcのトッ プディレクトリです – ctagsで作ったtagsファイルでジャンプしたいため

Slide 18

Slide 18 text

stubファイルを編集しスタブを追加

Slide 19

Slide 19 text

スタブを追加

Slide 20

Slide 20 text

関数を書きます ext/mbstring/mbstring.cを編集します。 まずは引数を取り、何もしない関数を作りま す。 引数はZEND_PARSE_PARAMETERS_START、 ZEND_PARSE_PARAMETERS_ENDで囲みま す。 $encodingが不正な場合は例外をスローしてい ます。

Slide 21

Slide 21 text

mbstringのルール ● 内部ではUTF-32で動いています(UCS方式) – たとえば、Shift_JISからEUC-JPでは ● Shift_JIS → UTF-32 → EUC-JP となります – データ型はuint32_tで取ります ● 32bit(4byte)ですね

Slide 22

Slide 22 text

内部で使える関数 ● mb_get_strlen – mb_strlenの内部実装関数です。 ● mb_get_substr – mb_substrの内部実装関数です。 ● mb_fast_convert – mb_convert_encodingの内部実装関数です。 ● mb_fast_convert関数で内部でUTF-32に変換して目的の文字エンコー ディングに変換しています、これがUCS方式

Slide 23

Slide 23 text

mb_fast_convertの実装 338行目でUTF-32 に変換し、341行目 でUTF-32から目的 のエンコーディン グに変換している

Slide 24

Slide 24 text

mb_get_strlenの実装 mb_fast_strlen_ utf8は難しいので 読まなくていい to_wcharメソッド がコードポイント長 を返すので、それを 足して返す実装に なってる

Slide 25

Slide 25 text

中身を作ります まず、 mb_get_substrで 1文字だけ取り除き ます。長さは短い 方を取ってくれま す。 次に、 mbfl_name2enco dingでEUC-JPのイ ンスタンスを取 得、 mb_fast_convert 関数で変換、 retを開放で終わり

Slide 26

Slide 26 text

動作確認 ハローワールドという文字列から、最初の1文字を抜き取ってEUC-JPに変換すること に成功しました! 出力の確認でmb_convert_encodingを挟んでいますが、mbstringのお作法がちょっ とでもわかると嬉しいです

Slide 27

Slide 27 text

テストの作成 ● テストを書きま しょう ● ext/mbstring/ tests/ mb_my_functio n.phpt に作成し ます

Slide 28

Slide 28 text

テストの実行 sapi/cli/php run-tests.php -P ext/mbstring/tests/mb_my_fun ction.phpt これで実行してPASS を確認します。

Slide 29

Slide 29 text

さらなる冒険へ ● これはちょっと高レベルな世界かと思われます ● もっと実装の方に行くと、さらなる知見が得られると 思います ● でも、既存のコードで新しい関数を開発することは 可能ですから、色々いじってみてください

Slide 30

Slide 30 text

おわり ● 今回はmb_my_function関数を作り、変換と substrを体験しました ● これだけでもちゃんと新しい関数が作れますが、C 言語の知識ともっとmbstringのソースコードの探 求をすると効率の良いコードが書けます ● Enjoy!