Upgrade to Pro — share decks privately, control downloads, hide ads and more …

var_dumpとvar_exportの理解から始めるPHPのソースコードリーディング

Masaki Yokoyama
December 21, 2024
260

 var_dumpとvar_exportの理解から始めるPHPのソースコードリーディング

PHP Conference Japan 2024 LT

PHP開発者ならおなじみのvar_dumpとvar_exportですが、これらの関数がどのように動いているのかを考えたことはありますか?

本発表では、var_dumpとvar_exportの違いを簡単に紹介し、それを切り口にPHPのソースコードを読み始める方法とそのメリットをお話したいと思います。PHPの内部動作を知ることで、デバッグや開発スキルをさらに向上させるきっかけを提供します!

Masaki Yokoyama

December 21, 2024
Tweet

Transcript

  1. まさき。
 2 About
 - NE株式会社 PHPer歴6年 
 - スクラムチームのプロダクトオーナーに挑戦中 


    - 副業でLaravelを教えている 
 - Xのアイコンは、「Twitterで猫になれるサービスnyan」で猫になってたらサービス終了して 戻れなくなった姿
 Like
 - ボードゲーム
 - Fitbit
 - サイクリング(真夏に小田原から江の島までチャリで行きました) 
 - (電気系の大学院卒なので)電子機器をいじる(分解する)! 
 - 旅客機を見る。(空港とか飛行機がテーマのドラマを見るのが好きっぽいことに気づいた) 
 @myblackcat7112
  2. PHP_FUNCTION
 16 Registering and using PHP functions 華氏(℉)を摂氏(℃)に変換する 関数、fahrenheit_to_celsius()を 定義する例


    
 少なくとも以下の2点が必要そ う
 1. PHP_FUNCTIONマクロで 関数を定義する
 2. PHP_FEマクロで関数を追 加する
 

  3. 24

  4. プロパティの名前修飾(mangling)を見てみる
 
 マングリングされたプロパティ名を Reflectionを使えば確認できるらしい ので実行してみた
 (普通に出力するだけだと\0という NULLバイト文字は出力されないので ひと工夫が必要)
 28 <?php

    declare(strict_types=1); class Hoge { private $prop; } class Foo { protected $prop; } class Bar { public $prop; } function print_mangling($obj) { $ref = new ReflectionObject($obj); foreach ($ref->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());
  5. 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バイト文字分を除外することでクラス名、プロパティ名を取得

  6. プロパティの出力結果がアクセス修飾子により異なる
 // 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プロパティ
 プロパティ名

  7. 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', ))
  8. コードを読んで分かった主な違いまとめ
 
 var_dump
 var_export
 引数
 複数指定可能
 1つのみ指定可能
 出力形式
 読みやすいデバッグ用の形式
 PHPコード


    文字列の出力方法
 php_printf
 smart_str_append系の関数
 参照の表示
 参照の場合&が表示される
 参照は明示されない
 オブジェクトのプロパティ
 アクセス修飾子ごとにキーの形 式が異なる
 アクセス修飾子に関係なく表示 される
 未初期化プロパティ
 未初期化プロパティであること が明示される
 未初期化プロパティは無視
 35