この記事では、主に PHP カーネルの zval を紹介します。これは、必要な友人が参照できるようにしています。 PHP で変数がどのように実装されるのかを尋ねたところ、残念ながら、おそらく構造体を使用して実装されているとしか答えられませんでした。この記事はGoogleの後にかなりよくまとめられていたので転載させていただき勉強になりました。
Text
ご存知のとおり、PHP の最下層は C 言語で実装されています。 PHP スクリプトは Zend エンジンによって C コードに解析され、実行されます。では、PHP 変数は C 言語ではどのように表現されるのでしょうか?最終的には何に解析されるのでしょうか?
答えはzvalです。 PHP 変数の種類に関係なく、PHP ソース コードでは zval と呼ばれる構造体で統一して表現されます。 zval は、C コードの PHP 変数のコンテナーとして見なされ、この変数の値、型、およびその他の関連情報が格納されます。それでは、zval の基本構造を見てみましょう (C 言語の基本的な知識が必要です)。
zvalの基本構造 PHPソースコードでは、zvalの構造はという名前のファイルにあります。以下は、関連するコードの抜粋です:
struct _zval_struct { zvalue_value value; /* value */ zend_uint refcount__gc; /* value of ref count */ zend_uchar type; /* active type */ zend_uchar is_ref__gc; /* if it is a ref variable */ }; typedef struct _zval_struct zval;
つまり、PHPソース内にあります。この構造体は PHP のさまざまなタイプの変数を表し、ガベージ コレクション (GC: Grabage Collection) などの他の関数も実装できます。 これは 4 つのフィールドで構成されており、それぞれがこの変数に関する特定の情報を表していることがわかります。
_zval_struct
的结构体(struct),具体定义在源代码的 Zend/zend.h
typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { /* string */ char *val; int len; } str; HashTable *ht; /* hash table value,used for array */ zend_object_value obj; /* object */} zvalue_value;
b などの一般的な代入操作は refcount を 1 増加させますが、unset() 操作はそれに応じて 1 減少します。 その値を判断してガベージコレクションを行うことができます。 PHP5.3 より前では、GC の実装に参照カウント メカニズムが使用されていました。zval の refcount が 0 に減少すると、Zend エンジンは zval を指す変数がないと判断し、zval が占有しているメモリ空間を解放します。ズヴァル。しかし、参照カウント機構を使用するだけでは循環参照の zval を解放できず、メモリ リーク (Memory Leak) が発生します。 5.3 より前では、このフィールドの名前はまだ refcount と呼ばれていました。5.3 以降、循環参照を処理するために新しいガベージ コレクション アルゴリズムが導入されたとき、作者はエラーを表示させるために refcount を操作するための多数のマクロを追加しました。より速く、名前は refcount__gc に変更され、refcount を操作するために全員がマクロを使用するようになりました。
同様に、4 番目のフィールド is_ref があり、この値は PHP の型が参照であるかどうかを示します。
PHP のガベージ コレクション メカニズムについて知りたい場合は、このブログを参照してください: PHP のガベージ コレクション メカニズム注: 変数はシンボルと呼ばれることもあります。すべてのシンボルはシンボル テーブルに存在し、スコープが異なると異なるシンボル テーブルが使用されます。このブログではこれについて説明します。
这个字段用于表明变量属于 PHP 8 种类型的哪种。在 zend 内部,这些类型对应于下面的宏(代码位置 phpsrc/Zend/zend.h):
#define IS_NULL 0#define IS_LONG 1#define IS_DOUBLE 2#define IS_BOOL 3#define IS_ARRAY 4#define IS_OBJECT 5#define IS_STRING 6#define IS_RESOURCE 7#define IS_CONSTANT 8#define IS_CONSTANT_ARRAY 9#define IS_CALLABLE 10
这个字段用于标记变量是否是引用变量。对于普通的变量,该值为 0,而对于引用型的变量,该值为 1。这个变量会影响 zval 的共享、分离等。它也和 PHP 的垃圾回收有关。
上述的 zval 结构,随着时间的发展,暴露出许多问题,例如占用空间大(24 字节)、不支持拓展、 对象和引用效率差等,所以在 PHP7 的时候,对 zval 进行了较大的改变,现在它的结构是这样的:
struct _zval_struct { union { zend_long lval; /* long value */ double dval; /* double value */ zend_refcounted *counted; zend_string *str; zend_array *arr; zend_object *obj; zend_resource *res; zend_reference *ref; zend_ast_ref *ast; zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; struct { uint32_t w1; uint32_t w2; } ww; } value; union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, /* active type */ zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) /* call info for EX(This) */ } v; uint32_t type_info; } u1; union { uint32_t var_flags; uint32_t next; /* hash collision chain */ uint32_t cache_slot; /* literal cache slot */ uint32_t lineno; /* line number (for ast nodes) */ uint32_t num_args; /* arguments number for EX(This) */ uint32_t fe_pos; /* foreach position */ uint32_t fe_iter_idx; /* foreach iterator index */ } u2; };
虽然看起来变得好大,但其实仔细看,它的字段都是联合体,这个新的 zval 在 64 位环境下,只需要 16 个字节(2 个指针 size)。PHP7 中的 zval,已经变成了一个值指针,它要么保存着原始值,要么保存着指向一个保存原始值的指针。
这部分内容来自鸟哥的GitHub。
zval 是一种 C 语言实现的数据结构,功能是作为 PHP 变量的容器;
它保存了变量的各种信息(如类型和值),并为其他功能(如垃圾回收)提供支持;
在不同的 PHP 版本中,它的结构不同。PHP7 的 zval 占 16 个字节,PHP5 的要占 24 个字节。
PHP内核探索之变量(1)变量的容器-Zval
PHP垃圾回收深入理解
深入理解PHP7之zval
相关推荐:
以上がPHP カーネル zvalの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。