変数の基本構造
PHP 変数は弱く型指定されており、変数を指定する必要がないことは誰もが知っています。宣言するときにタイプします。では、これはどのように実装されるのでしょうか?これは変数の基本構造から始める必要があります。
zval の実装
ソース コード ファイル zend_type.h で、zval の定義を確認できます。
typedef struct _zval_struct zval; struct _zval_struct { zend_value value; /* 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 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 */ uint32_t access_flags; /* class constant access flags */ uint32_t property_guard; /* single property guard */ uint32_t extra; /* not further specified */ } u2; }
zval 構造体は、以下を保持する値またはポインターで構成されます。変数のタイプ。共用体 zend_value と 2 つの共用体 u1 および u2 形式
- u1
u1 は、変数のタイプとその情報、および内部のフィールドを保存するために使用されます。用途は次のとおりです。
type: レコード変数の型。 u2.v.type: 変数の固有の型に対応するフラグ (定数型、参照カウント型、不変型など) を介して
type_flags にアクセスできます。変数の型が異なれば、フラグも異なります。
const_flags: 定数型フラグ
reserved: 予約済みフィールド
- u2
u2 は主に補助関数です。構造 メモリはアライメントされているため、u2 のスペースは u2 の有無にかかわらずすでにスペースを占有しているため、それが使用されます。 u2 の補助フィールドには多くの型情報が記録されます。これは内部関数にとって非常に有益であり、キャッシュの使いやすさを向上させたり、メモリのアドレス指定操作を減らしたりします。ここではその一部を紹介します。
next: ハッシュ競合の問題 (ハッシュ競合はまだ理解されていません) を解決し、競合の次の要素の位置を記録するために使用されます。
cache_slot: ランタイムキャッシュ。関数を実行すると、まずキャッシュ内を検索し、キャッシュ内に見つからない場合は、グローバル関数テーブル内を検索します。
num_args: 関数の呼び出し時に渡されるパラメータの数
access_flags: public protected private などのオブジェクト クラスのアクセス フラグ。
- zend_value
typedef union _zend_value { zend_long lval; /* 整型*/ double dval; /* 浮点型 */ 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; } zend_value;
zend__value からわかるように、long 型と double 型は値を直接格納しますが、他の型はそれぞれの構造体を指すポインターです。したがって、zval の構造により、変数に割り当てる値の型に関係なく、対応する記憶構造を見つけるのに役立つため、PHP 変数は宣言時に型を明示的に指定する必要がありません。
値が文字列である変数を例にとると、その構造は次のとおりです:
PHP5 と PHP7 の zval 構造の比較
- PHP5
- PHP7
php7 の zval は合計 16 バイトしか占有しないことがわかります。これにより、PHP5 の zval が占有する 48 バイトと比較して、多くのメモリが節約されます。 。
また、PHP5では変数はすべてヒープに配置されますが、一時変数についてはヒープに適用する必要はありません。したがって、これは PHP7 で最適化されており、一時変数はスタックに直接適用されます。
一般的な変数のタイプ
以下では、変数構造の一般的なタイプをいくつか紹介します。その他のタイプについては、ソース コードをご自身で参照してください。
整数と浮動小数点型
整数と浮動小数点型の場合、スペースが小さいため、整数値は zval に直接格納され、浮動小数点型に格納されます。 type 値は dval に格納されます。
typedef union _zend_value { zend_long lval; /* 整型*/ double dval; /* 浮点型 */ ... }
String
PHP 7 では新しい文字列構造が定義されています。構造は次のとおりです。
struct _zend_string { zend_refcounted_h ; zend_ulong h; /* hash value */ size_t len; char val[1]; };
上記の各フィールドの意味:
gc: 変数参照情報。参照カウントを使用するすべての変数タイプがこの構造になります。
h: 配列内のインデックスを計算するときに使用されるハッシュ値。 (この操作により PHP7 のパフォーマンスが 5% 向上すると言われています)
len: 文字列の長さ、この値によってバイナリのセキュリティが確保されます
val: 文字列の内容、可変長の構造体、プレスlen の長さを割り当てる場合、メモリに適用されます
array
array は、PHP の非常に強力なデータ構造です。その基礎となる実装は、通常の順序付けされた HashTable です。ここでは、その構造を簡単に説明します。詳細については後ほど説明します。
typedef struct _zend_array HashTable; struct _zend_array { zend_refcounted_h gc; union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar flags, zend_uchar nApplyCount, zend_uchar nIteratorsCount, zend_uchar consistency) } v; uint32_t flags; } u; uint32_t nTableMask; Bucket *arData; uint32_t nNumUsed; uint32_t nNumOfElements; uint32_t nTableSize; uint32_t nInternalPointer; zend_long nNextFreeElement; dtor_func_t pDestructor; }
オブジェクト
PHP7 のオブジェクト構造も再設計されており、PHP5 の実装とは大きく異なります。
struct _zend_object { zend_refcounted_h gc; uint32_t handle; zend_class_entry *ce; const zend_object_handlers *handlers; HashTable *properties; zval properties_table[1]; };
ここにいくつかのフィールドがあります:
gc: gc header
*ce: オブジェクト クラスに対応するクラス
*properties: HashTable Structure 、keyはオブジェクトの属性名、valueはproperties_tables配列内の属性値のオフセットであり、対応する属性値はオフセットを通じてproperties_talbeで見つかります。
properties_talbe[1]: オブジェクトの属性値を格納します
わかりました。まずここにこれを書きましょう。