PHP カーネル zval

不言
リリース: 2023-03-24 11:12:02
オリジナル
2799 人が閲覧しました

この記事では、主に PHP カーネルの zval を紹介します。これは、必要な友人が参照できるようにしています。 PHP で変数がどのように実装されるのかを尋ねたところ、残念ながら、おそらく構造体を使用して実装されているとしか答えられませんでした。この記事はGoogleの後にかなりよくまとめられていたので転載させていただき勉強になりました。

Text

PHPのデータ型

C、C++、Javaなどの他のプログラミング言語と比較して、PHPは弱い型指定言語です。 、その型を宣言する必要はありません。この機能は私たちに多くの利便性をもたらしますが、場合によっては落とし穴ももたらします。では、PHP には本当にデータ型がないのでしょうか?


もちろん違います。 PHP 公式ドキュメントでは、PHP の変数はスカラー型、複合型、特殊型の 3 つのカテゴリに分類されています。スカラー型には bool、int、float、string が含まれ、複合型には配列とオブジェクトが含まれ、特殊型には NULL とリソースが含まれます。したがって、PHP 変数の内訳としては、8 つのデータ型があります。

ご存知のとおり、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 つのフィールドで構成されており、それぞれがこの変数に関する特定の情報を表していることがわかります。


ZVALUE_VALUE VALUE

_zval_struct 的结构体(struct),具体定义在源代码的 Zend/zend.h

valueは、変数の実際の値を表すために使用されます。具体的には、zvalue_value:

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;
ログイン後にコピー

の結合です。_zvalue_valueには5つのフィールドしかありませんが、PHPでは8つのフィールドがあることがわかります。データ型では、5 つのフィールドを使用して 8 つの型を表すにはどうすればよいでしょうか?

これは、フィールドを再利用することでフィールドを削減するという目的を達成する、PHP の賢い設計であると考えられます。たとえば、PHP 内では、ブール型、整数、リソース (リソースの識別子が保存されている場合) は lval フィールドを介して保存されます。str は文字列を保存します。 PHP では、配列は実際にはハッシュ テーブルです)、obj はオブジェクトの種類を格納します。すべてのフィールドが 0 または NULL に設定されている場合、PHP では NULL を意味するため、8 種類の値を格納するために 5 つのフィールドが使用されます。

ZEND_UINT REFCOUNT__GC

そのサフィックス gc から、このフィールドがガベージ コレクションに関連していることがわかります。

実際には、この zval を指す変数の数を保存するカウンターです。変数が生成されると、1、つまり refcount = 1 に設定されます。

変数に対してさまざまな操作を実行すると、その値が変更されます。


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 のガベージ コレクション メカニズム

注: 変数はシンボルと呼ばれることもあります。すべてのシンボルはシンボル テーブルに存在し、スコープが異なると異なるシンボル テーブルが使用されます。このブログではこれについて説明します。

ZEND_UCHAR TYPE


这个字段用于表明变量属于 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
ログイン後にコピー

ZEND_UCHAR IS_REF__GC


这个字段用于标记变量是否是引用变量。对于普通的变量,该值为 0,而对于引用型的变量,该值为 1。这个变量会影响 zval 的共享、分离等。它也和 PHP 的垃圾回收有关。

PHP7中的zval


上述的 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。

总结


  1. zval 是一种 C 语言实现的数据结构,功能是作为 PHP 变量的容器;

  2. 它保存了变量的各种信息(如类型和值),并为其他功能(如垃圾回收)提供支持;

  3. 在不同的 PHP 版本中,它的结构不同。PHP7 的 zval 占 16 个字节,PHP5 的要占 24 个字节。

参考


PHP内核探索之变量(1)变量的容器-Zval
PHP垃圾回收深入理解
深入理解PHP7之zval

相关推荐:

PHP内核之探究内存管理与缓存机制

PHP内核分析-Zend虚拟机详解

以上がPHP カーネル zvalの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート