ホームページ >バックエンド開発 >PHPチュートリアル >PHP は変数をどのように保存するのでしょうか? zval構造を理解していますか?
PHP ソースコードの
PHP で変数を定義する場合、型を宣言する必要はなく、最初は変数 $a に整数値が代入されていますが、これは簡単に変更できます。他のタイプは後ほど。では、この変数 $a は PHP ソース コードにどのように格納されるのでしょうか?この疑問を念頭に置いて、PHP のソース コードを見てみましょう。
PHP のソース コードは C で書かれています。PHP コードで作成された変数を格納するために、PHP ソース コードでは zval 構造体が使用されます。 zval 構造の定義を取り出して簡単に分析してみましょう。
これは Github 上の PHP の公式リポジトリです: github.com/php/php-src. この記事で使用されているブランチは PHP-7.4.29 です。
zval 構造
PHP ソース コードでこのファイルを見つけます: php-src/Zend/zend_types.h。zval 構造が次のように定義されていることがわかります。 、左側がソースコードです。ソース コードでは、PHP 独自に定義された型 zend_uchar、uint16_t、uint32_t などを使用します。これらの型は、さまざまなプラットフォームやそのプラットフォーム用のコンパイラーでは char short int などに変換されます。理解しやすいように、一般的な型に翻訳してソースコードの右側に表示しました。同時にマクロ関数 ZEND_ENDIAN_LOHI_3() も拡張されます。
typedef struct _zval_struct zval; ... 《源代码》 《翻译后》 ------------------------------------------------------------------------------------------- struct _zval_struct { | struct _zval_struct { zend_value value; | zend_value value; union { | union { struct { | struct { ZEND_ENDIAN_LOHI_3( | unsigned char type; zend_uchar type, | unsigned char type_flags; zend_uchar type_flags, | union { union { | unsigned short extra; uint16_t extra; | } u; } u | } v; ) | unsigned int type_info; } v; | } u1; uint32_t type_info; | union { } u1; | unsigned int next; union { | unsigned int cache_slot; uint32_t next; | unsigned int opline_num; uint32_t cache_slot; | unsigned int lineno; uint32_t opline_num; | unsigned int num_args; uint32_t lineno; | unsigned int fe_pos; uint32_t num_args; | unsigned int fe_iter_idx; uint32_t fe_pos; | unsigned int access_flags; uint32_t fe_iter_idx; | unsigned int property_guard; uint32_t access_flags; | unsigned int constant_flags; uint32_t property_guard; | unsigned int extra; uint32_t constant_flags; | } u2; uint32_t extra; | }; } u2; | }; |
zval 構造体では、変数の値は zend_value 型の value 属性に格納されます。そして、u1.v.type を使用して、この値の型を記録します。たとえば、IS_LONG は整数型に対応し、IS_STRING は文字列型に対応します。
zend_value Union
zend_value 型は php-src/Zend/zend_types.h にも定義されており、ユニオンです。 、左側がソースコードです。また、右側では、見やすくするために zend_long uint32_t を一般的な型に変換する簡単な変換も行いました。
《源代码》 《翻译后》 ------------------------------------------------------------------------------------ typedef union _zend_value { | typedef union _zend_value { zend_long lval; /* long value */ | long lval; double dval; /* double value */ | double dval; zend_refcounted *counted; | zend_refcounted *counted; zend_string *str; | zend_string *str; zend_array *arr; | zend_array *arr; zend_object *obj; | zend_object *obj; zend_resource *res; | zend_resource *res; zend_reference *ref; | zend_reference *ref; zend_ast_ref *ast; | zend_ast_ref *ast; zval *zv; | zval *zv; void *ptr; | void *ptr; zend_class_entry *ce; | zend_class_entry *ce; zend_function *func; | zend_function *func; struct { | struct { uint32_t w1; | unsigned int w1; uint32_t w2; | unsigned int w2; } ww; | } ww; } zend_value; | } zend_value;
共用体の特徴の 1 つは、共用体が占有するメモリがその属性の最大の型に対応する長さであることです。このうちzend_longはlong型であり、long型のlvalとdouble型のdvalの長さがともに8バイトであることがわかります。内部の他のポインター型も 8 バイトです。最後の構造体属性 ww は 2 つの int 型で構成されており、合わせた長さも 8 バイトになります。したがって、この共用体の長さは 8 バイトになります。
私たちが記述する PHP コードでは、整数および浮動小数点データの値が lval および dval に直接格納されます。文字列、配列、またはその他の型の場合、データを保存するためにスペースが割り当てられ、そのアドレスが zval.value 属性である zend_value に保存されます (例: zval.value.zend_long = 9527, zval) .value.zend_string = 文字列アドレス、zval.value.zend_array = 配列アドレス。次に、zval.u1.v.type で、この zval.value が整数、浮動小数点、文字列、またはその他の型であることをマークします。
zval.u1.v.type タイプ定義は php-src/Zend/zend_types.h ファイルにもあります。すべての定義は次のとおりです:
/* regular data types */ #define IS_UNDEF 0 #define IS_NULL 1 #define IS_FALSE 2 #define IS_TRUE 3 #define IS_LONG 4 #define IS_DOUBLE 5 #define IS_STRING 6 #define IS_ARRAY 7 #define IS_OBJECT 8 #define IS_RESOURCE 9 #define IS_REFERENCE 10 /* constant expressions */ #define IS_CONSTANT_AST 11 /* internal types */ #define IS_INDIRECT 13 #define IS_PTR 14 #define IS_ALIAS_PTR 15 #define _IS_ERROR 15 /* fake types used only for type hinting (Z_TYPE(zv) can not use them) */ #define _IS_BOOL 16 #define IS_CALLABLE 17 #define IS_ITERABLE 18 #define IS_VOID 19 #define _IS_NUMBER 20
zval 構造体のメモリ使用量
次に、zval に必要なメモリを分析します。
value: zend_value タイプ 8 バイト。
u1:
u1.v.type: unsigned char 1 バイト、u1.v.type_flags : unsigned char 1 バイト、u1.v.u: 2 バイトの結合に unsigned short 追加属性が 1 つだけあるため、u1.v の構造は合計 4 バイトになります。
u1.type_info: unsigned int 4 バイト。
したがって、共用体 u1 の長さは、最長の属性の長さ (4 バイト) になります。
u2: これも int 型の属性を含む共用体なので、長さは 4 バイトです。
したがって、zval が占有する合計メモリは 8 4 4 = 16 バイトになります。
つまり、PHP コードを作成するときに整数変数を作成すると、実際には操作中に 16 バイトのメモリを占有し、メモリ オーバーヘッドが C の少なくとも 2 倍になります。言語。もちろん、この 2 つのオーバーヘッドにより、PHP の変数処理の柔軟性も得られます。
推奨学習: 「PHP ビデオ チュートリアル 」
以上がPHP は変数をどのように保存するのでしょうか? zval構造を理解していますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。