Slide 1

Slide 1 text

NE株式会社 まさき。
 var_dumpとvar_exportの理解から始めるPHPのソー スコードリーディング
 PHP Conference Japan 2024 12/22 1

Slide 2

Slide 2 text

まさき。
 2 About
 - NE株式会社 PHPer歴6年 
 - スクラムチームのプロダクトオーナーに挑戦中 
 - 副業でLaravelを教えている 
 - Xのアイコンは、「Twitterで猫になれるサービスnyan」で猫になってたらサービス終了して 戻れなくなった姿
 Like
 - ボードゲーム
 - Fitbit
 - サイクリング(真夏に小田原から江の島までチャリで行きました) 
 - (電気系の大学院卒なので)電子機器をいじる(分解する)! 
 - 旅客機を見る。(空港とか飛行機がテーマのドラマを見るのが好きっぽいことに気づいた) 
 @myblackcat7112

Slide 3

Slide 3 text

今日伝えたいこと!
 - プログラミング言語「PHP」も別のプログラミング言語で書かれている!
 - PHPのソースコードリーディングをすることで、PHPの細かい仕様に詳しくな れる!
 - PHPのコードリーディングをするのは難しそうだなと思っていたが、読んで みると意外と読めて面白かったのでみなさんにも読んでみてもらいたい!
 3

Slide 4

Slide 4 text

PHPはプログラミング言語!


Slide 5

Slide 5 text

PHPはプログラミング言語!


Slide 6

Slide 6 text

PHPは世界で書かれているプログラミング言語
 6 The RedMonk Programming Language Rankings: January 2024 – tecosystems

Slide 7

Slide 7 text

PHPはソースが公開されているプログラミング言語!
 7 php/php-src

Slide 8

Slide 8 text

PHPはC言語で書かれたプログラミング言語
 8 GitHub - php/php-src: The PHP Interpreter

Slide 9

Slide 9 text

PHPはC言語で書かれたプログラミング言語
 9 GitHub - php/php-src: The PHP Interpreter

Slide 10

Slide 10 text

10 つまり、C言語がある程度読めれば、
 PHPのソースって読めちゃったりする???


Slide 11

Slide 11 text

var_dumpくん、文字列を渡してもインスタンスを渡しても ちゃんと動いているけどさ、いったいきみはどういう仕組み で動いてるの?
 11

Slide 12

Slide 12 text

var_dumpくん、文字列を渡してもインスタンスを渡しても ちゃんと動いているけどさ、いったいきみはどういう仕組み で動いてるの?
 12 って、思ってるけど、
 PHPのソースを読めば解決しちゃったりする????
 


Slide 13

Slide 13 text

13 ってなわけで、var_dumpとvar_exportのコードを
 読んでみたので抜粋してご紹介!!
 (時間の関係上、var_exportはあまり触れません)


Slide 14

Slide 14 text

var_dumpでリポジトリを検索!
 14

Slide 15

Slide 15 text

var_dumpでリポジトリを検索!
 15

Slide 16

Slide 16 text

PHP_FUNCTION
 16 Registering and using PHP functions 華氏(℉)を摂氏(℃)に変換する 関数、fahrenheit_to_celsius()を 定義する例
 
 少なくとも以下の2点が必要そ う
 1. PHP_FUNCTIONマクロで 関数を定義する
 2. PHP_FEマクロで関数を追 加する
 


Slide 17

Slide 17 text

ext/standard/var.c
 17 PHP_FUNCTIONで検索するといくつか見覚えのある関数たちが!


Slide 18

Slide 18 text

マニュアル: 変数操作 関数 にあるものが多かった
 
 
 18 PHP: 変数操作 関数 - Manual 
 https://www.php.net/manual/ja/ref.var.php 


Slide 19

Slide 19 text

var_dumpをマニュアルで確認する
 19 PHP: var_dump - Manual ダンプしたい変数は複数指定できる


Slide 20

Slide 20 text

PHP_FUNCTION(var_dump)
 20 https://github.com/php/php-src/blob/master/ext/standard/var.c#L234 var_dumpは引数を複数指定で きるので、
 引数ごとにloopを回して php_var_dump関数を呼び出して いる


Slide 21

Slide 21 text

php_var_dump関数
 21 https://github.com/php/php-src/blob/master/ext/standard/var.c#L103 再帰呼び出し前提の関数
 - このファイル内で再帰呼び出ししている (配列のところとか)
 - 引数のlevelでインデントの数を指定して いる


Slide 22

Slide 22 text

php_var_dump関数が再帰で呼び出されている例
 22 arrayの中身を出力するところ
 値を出力する部分は、php_var_dumpを再帰的に呼び出している


Slide 23

Slide 23 text

php_var_dump関数 23 https://github.com/php/php-src/blob/master/ext/standard/var.c#L103 switch-case文で与えられた値の型ごとに出力 するものを変えている
 - php_printfで出力
 - 配列やオブジェクトは、再帰的に値を取得 して表示する
 


Slide 24

Slide 24 text

24

Slide 25

Slide 25 text

var_dumpとvar_exportのオブジェクトの処理での発見
 - zend_unmangle_property_nameという処理が呼ばれている
 - var_dumpではプロパティのアクセス修飾子によって表示が変わる
 - var_exportではアクセス修飾子によらず全プロパティが表示される
 25

Slide 26

Slide 26 text

zend_unmangle_property_name
 26 var_dumpではクラス名とプロパティ名を取得する処理をやっている


Slide 27

Slide 27 text

プロパティの名前修飾(mangling)
 privateやprotectedのプロパティに外部からアクセスできないのは、
 内部で別のプロパティ名に変更されてしまっているから。
 privateのプロパティの値である
 “value”を取得したいのに取れてないの図
 27

Slide 28

Slide 28 text

プロパティの名前修飾(mangling)を見てみる
 
 マングリングされたプロパティ名を Reflectionを使えば確認できるらしい ので実行してみた
 (普通に出力するだけだと\0という NULLバイト文字は出力されないので ひと工夫が必要)
 28 getProperties() as $prop) { $prop->setAccessible(true); $mangled_name = $prop->getName(); echo "Class:{$ref->getName()}, Property: {$mangled_name}, "; $prop_array = (array) $obj; foreach ($prop_array as $key => $value) { for($i = 0; $i < strlen($key); $i++) { if ($key[$i] === "\0") { $mangled_name = str_replace("\0", "\\0", $key); break; } } echo "Mangled Name: {$mangled_name} \n"; } } } print_mangling(new Hoge()); print_mangling(new Foo()); print_mangling(new Bar());

Slide 29

Slide 29 text

プロパティの名前修飾(mangling)を見てみる
 値取れた!!!!!
 29

Slide 30

Slide 30 text

zend_unmangle_property_name_exでやってる
 *class_name = ZSTR_VAL(name) + 1; anonclass_src_len = zend_strnlen(*class_name + class_name_len + 1, ZSTR_LEN(name) - class_name_len - 2); if (class_name_len + anonclass_src_len + 2 != ZSTR_LEN(name)) { class_name_len += anonclass_src_len + 1; } *prop_name = ZSTR_VAL(name) + class_name_len + 2; if (prop_len) { *prop_len = ZSTR_LEN(name) - class_name_len - 2; } return SUCCESS; 30 https://github.com/php/php-src/blob/master/Zend/zend_compile.c#L1608 先頭のNULLバイト文字分を除外することでクラス名、プロパティ名を取得


Slide 31

Slide 31 text

プロパティの出力結果がアクセス修飾子により異なる
 // var_dump(new Hoge); object(Hoge)#1 (3) { ["amount":"Hoge":private]=> int(0) ["name":protected]=> string(4) "Hoge" ["value"]=> string(4) "hoge" } 31 privateプロパティ
 プロパティ名:クラス名:private
 
 Protectedプロパティ
 プロパティ名:protected
 
 publicプロパティ
 プロパティ名


Slide 32

Slide 32 text

プロパティ名を出力しているところ
 
 32 https://github.com/php/php-src/blob/master/ext/standard/var.c#L65

Slide 33

Slide 33 text

var_exportでは全プロパティが連想配列で表示されている
 33 class Hoge { private int $amount = 0; protected string $name = 'Hoge'; public string $value = 'hoge'; } // var_export(new Hoge); \Hoge::__set_state(array( 'amount' => 0, 'name' => 'Hoge', 'value' => 'hoge', ))

Slide 34

Slide 34 text

var_exportでは値だけ取得している
 34 unmangled_nameを用いて値だけ取得して、php_object_element_exportを呼び出して出力 している


Slide 35

Slide 35 text

コードを読んで分かった主な違いまとめ
 
 var_dump
 var_export
 引数
 複数指定可能
 1つのみ指定可能
 出力形式
 読みやすいデバッグ用の形式
 PHPコード
 文字列の出力方法
 php_printf
 smart_str_append系の関数
 参照の表示
 参照の場合&が表示される
 参照は明示されない
 オブジェクトのプロパティ
 アクセス修飾子ごとにキーの形 式が異なる
 アクセス修飾子に関係なく表示 される
 未初期化プロパティ
 未初期化プロパティであること が明示される
 未初期化プロパティは無視
 35


Slide 36

Slide 36 text

(おまけ) カスタムvar_dumpとマニュアル修正
 php.netのマニュアル本体のリポジトリ 
 https://github.com/php/web-php/tre e/master/manual 
 
 php.netでマニュアルを修正するときの マニュアル
 https://doc.php.net/guide/editing.md 
 
 ローカルでphp.netを起動する方法 
 https://wiki.php.net/web/mirror 
 36

Slide 37

Slide 37 text

(おまけ) カスタムvar_dumpとマニュアル修正
 37

Slide 38

Slide 38 text

(おまけ) カスタムvar_dumpとマニュアル修正
 
 src-build/php-practice-docker/php-src/ext/st andard/basic_functions_arginfo.h 
 ファイルに以下を追加することで、 
 PHPの標準関数として認識された。 
 38 ZEND_FUNCTION(var_dump_custom); ZEND_FE(var_dump_custom, arginfo_var_dump);

Slide 39

Slide 39 text

(おまけ) カスタムvar_dumpとマニュアル修正
 39

Slide 40

Slide 40 text

(おまけ) カスタムvar_dumpとマニュアル修正
 40 表示された!!!!


Slide 41

Slide 41 text

まとめ
 - PHPはC言語で書かれていてソースコードも公開されている
 - ゆえにソースコードリーディングをすることでPHPがどのように動いている のかを理解することができる
 - var_dumpとvar_exportを題材にどうやってコードを読んだのかを共有した
 - その過程で得られた学びを共有し、実際に手を加えて動かすところまで やった
 - ソースコードリーディングのハードルを下げることができたら嬉しい
 41