PHP7 カーネル分析 3 変数

不言
不言オリジナル
2018-04-13 14:54:041518ブラウズ

この記事の内容は、PHP7 カーネル解析 1 の CGI と FastCGI についてです。必要な友達に参考にしてください。

1. 変数の構造


2.

typedef struct _zval_struct     zval;

typedef union _zend_value {
    zend_long         lval;    //int整形
    double            dval;    //浮点型
    zend_string      *str;     //string字符串
    zend_array       *arr;     //array数组
    zend_object      *obj;     //object对象
    zend_resource    *res;     //resource资源类型
    zend_reference   *ref;     //引用类型,通过&$var_name定义的
} zend_value;

struct _zval_struct {
    zend_value        value; //变量实际的value
    union {
        struct {
            ZEND_ENDIAN_LOHI_4( 
                zend_uchar    type,         //变量类型
                zend_uchar    type_flags,  //类型掩码,不同的类型会有不同的几种属性,内存管理会用到
                zend_uchar    const_flags,
                zend_uchar    reserved)
        } v;
        uint32_t type_info; //上面4个值的组合值,可以直接根据type_info取到4个对应位置的值
    } u1;
    union {
        uint32_t     var_flags;
        uint32_t     next;  //哈希表中解决哈希冲突时用到   
        uint32_t     cache_slot;   
        uint32_t     lineno;    
        uint32_t     num_args;    
        uint32_t     fe_pos;  
        uint32_t     fe_iter_idx;
    } u2;
};
このうち、undef、true、false、nullは値を持たず型によって直接区別されますが、longとdoubleの値はvalueに直接格納され、その他の型はポインタになります


3. 文字列

#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


4. 配列

typedef struct _zend_string   zend_string;

struct _zend_string {
    zend_refcounted_h gc;  //变量引用信息,比如当前value的引用数
    size_t            len;  //字符串长度,通过这个值保证二进制安全
    char              val[1]; //字符串内容,变长struct,分配时按len长度申请内存
};
HashTable は、要素の保存とインデックス付けを実現するために主に arData に依存します。要素を挿入するときは、まず要素を Bucket 配列に順番に挿入します。位置は idx です。次に、キーのハッシュ値に従ってハッシュ テーブル内の特定の位置 nIndex にマッピングし、この位置に idx を格納します。検索時は、まずハッシュテーブルMap to nIndexでBucket配列内のvalueの位置idxを取得し、その後Bucket配列から要素を取り出します。

typedef struct _zend_array HashTable;
typedef struct _zend_array zend_array;

typedef struct _Bucket {
    zval              val; //存储的具体value,这里嵌入了一个zval,而不是一个指针
    zend_ulong        h;   //哈希值
    zend_string      *key; //key值
} Bucket;

struct _zend_array {
    zend_refcounted_h gc; //引用计数信息
    uint32_t          nTableMask;  //计算bucket索引时的掩码,用于散列表的计算nIndex
    Bucket           *arData;     //bucket数组
    uint32_t          nNumUsed;   //已用bucket数
    uint32_t          nNumOfElements; //已有元素数,nNumOfElements <= nNumUsed,因为删除的并不是直接从arData中移除
    uint32_t          nTableSize; //数组的大小,为2^n,默认为8
    uint32_t          nInternalPointer; //数值索引,用于HashTable遍历
    zend_long         nNextFreeElement;//下一个空闲可用位置的数字索引
    dtor_func_t       pDestructor;//析构函数,销毁时调用的函数指针
};

PHP7 カーネル分析 3 変数ハッシュ衝突: 衝突が発生した場合、元の値の位置を新しい値の zval.u2.next に保存し、元の値の位置を新しい値で置き換えます

拡張: PHP ハッシュ テーブルのサイズは 2^n です。容量が足りない場合は、まず削除された要素の割合を確認します。しきい値に達した場合は、削除された要素が削除され、インデックスが再構築されます。到達していない場合は、容量を現在のサイズの 2 倍に拡張し、現在のバケット配列を新しい領域にコピーして、インデックスを再構築します。
ハッシュテーブルの再構築: 削除された要素が一定数に達した場合や容量が拡張された場合、バケットの位置で値が移動したり、ハッシュ配列nTableSizeが変更され、ハッシュテーブル間のマッピング関係が発生したりするため、ハッシュテーブルを再構築する必要があります。再構築プロセスでは、実際には配列内のバケットの値を走査し、マップされた値を再計算してハッシュ テーブルに更新し、削除された値を削除し、その後の削除されていない値を順に移動します


5. リファレンス

リファレンスは、PHP では特別です。これを変更すると、実際に指す zval が直接変更されます。PHP では、単にポインタとして理解できます。 、参照変数は & 演算子によって生成されます。つまり、前の型が何であったとしても、& は最初に zval が埋め込まれた zend_reference 構造体を作成します。この zval の値は、元の zval の値を指します。 (ブール値、整数、または浮動小数点の場合は、元の値が直接コピーされます)、その後、元の zval の型が IS_REFERENCE に変更され、元の zval の値は、新しく作成された zend_reference 構造体を指します。

$arr["a"] = 1;
$arr["b"] = 2;
$arr["c"] = 3;
$arr["d"] = 4;

unset($arr["c"]);


6. 参照カウント

typedef struct _zend_reference  zend_reference;

struct _zend_reference {
    zend_refcounted_h gc;
    zval              val;
};
typedef struct _zend_refcounted_h {
    uint32_t         refcount;         
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar    type,
                zend_uchar    flags,   
                uint16_t      gc_info)  
        } v;
        uint32_t type_info;
    } u;
} zend_refcounted_h;
すべてのデータ型が参照カウントを使用するわけではありません。値がポインターである型のみが参照を使用できます。数えています。 zval.u1.type_flag


7. Copy on write

実際には文字列と配列のみがサポートされていますPHP7 カーネル分析 3 変数

8。


PHP 変数のリサイクルには、主に 2 つのタイプがあります: アクティブな破壊と自動的な破壊です。アクティブな破棄は設定を解除することを指し、自動破棄は PHP の自動管理メカニズムであり、明示的なリターンがなくても、PHP が自動的にこの操作を追加します。元の値を指している場合は、切断後の古い値のrefcountもチェックされます。

$a = "time:" . time();   //$a       ->  zend_string_1(refcount=1)
$b = $a;                 //$a,$b    ->  zend_string_1(refcount=2)
$c = $b;                 //$a,$b,$c ->  zend_string_1(refcount=3)

unset($b);               //$b = IS_UNDEF  $a,$c ->  zend_string_1(refcount=2)
unset($a) 前:

unset($a) 後: PHP7 カーネル分析 3 変数

関連する推奨事項: PHP7 カーネル分析 3 変数

PHP7 カーネル分析1 CGI と FastCGI

PHP7 カーネル分析 2 I/O モデル

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

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。