PHPでの変数の配置方法

単純な質問のように思えますが、何に答えるべきかさえ明確ではありませんよね?

変数を作成する方法、変数の値を取得する方法、最後に変数への参照を取得する方法を知っています。

しかし、彼らはどのように内部から機能するのでしょうか?

変数の値を変更すると、インタープリターで何が起こりますか? それともいつ削除しますか?

変数タイプはどのように実装されますか?



この記事では、これらのトピックを明らかにしようとします。



アブストラクト


PHPの変数は、変数の型、値、このコンテナを参照する変数の数、およびこの変数が参照であるかどうかのフラグを格納する特定のコンテナの形式で表現されます。







構造とポインターに関する余談


Cで記述したことがない場合は、おそらくここで非常に広く使用されている構造やポインターのようなものについては知らないでしょう。

構造体はクラスに非常に似ており、メソッド、データ、データへのポインター、および関数へのポインターのみを持つことができません。 Cで構造体を宣言することで、データ型を定義し、変数を定義するときに、変数の型の代わりにこの構造体の名前を次のように記述できます。

my_super_struct super_struct_instance;
      
      





ポインターは参照変数のようなもので、その値のみがメモリ内のアドレスです。 実際、これらはポインターとしての参照であり、参照解除されたポインターのようにのみ動作します。 コードに表示する方が良い:

 //   foo,       int int *foo; //    int int bar = 3; //     bar    . //  foo    ,    bar foo = &bar; //       (    ) //    (*foo)++; //      ,     //        foo++;
      
      









コンテナ


コンテナはzvalと呼ばれる構造体で、次のようになります。

 struct zval { zvalue_value value; zend_uchar type; //  ,    char zend_uchar is_ref; zend_ushort refcount; };
      
      





ご覧のとおり、値、型、フラグ、および参照変数の数があります。

次のようなタイプがあります。



zvalue_valueは共用体です。 Unionは、異なる型の複数のメンバーを宣言できる型ですが、最終的には1つだけが使用されます。これは、次のように定義される方法です。

 typedef union _zvalue_value { long lval; // integer double dval; // float struct { char *val; int len; } str; // string HashTable *ht; // array zend_object obj; // object } zvalue_value;
      
      





その結果、この型の変数を作成すると、ユニオンの最も重い要素とまったく同じ量のメモリが使用されます。





なぜそんなに?


ここで分析します-なぜ、たとえば、ここになんらかの参照がありますか?

また、非常に簡単です。変数に別の変数の値を割り当てると、両方が同じzvalを参照し、refcountがインクリメントされます。



ここに犬のいるオリジナル)



これらの変数のいずれかの値を変更する場合、refcountが1を超えると、PHPはこのzvalをコピーし、そこに変更を加えると、変数はすでに新しいzvalを指します。

これを少し形式化すると、次のようになります。

Php ボンネットの下
 $foo = "asd"; $bar = $foo;
      
      



 bar,foo: { type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 2 }
      
      



 $bar .= "q";
      
      



 foo: { type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 1 } bar: { type: string, value: str: val: "asdq" len: 4 is_ref: 0 refcount: 1 }
      
      





この手法は、コピーオンライトと呼ばれ、メモリ消費を大幅に削減するのに役立ちます。

また、ガベージコレクターにはrefcountが必要です。これにより、refcount = 0のすべてのzval-sがメモリから削除されます。



そして、リンクで何をすべきか、そしてなぜこれはis_refなのでしょうか?


リンクはどうなりますか? すべてが非常に簡単です。変数からリンクを作成すると、is_refフラグが1になり、上記の最適化はこのzvalに適用されなくなります。 コードを説明します。

Php ボンネットの下
 $foo = "asd"; $bar = $foo;
      
      



 bar,foo: { type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 2 }
      
      



 $zxc = &$foo;
      
      



 zxc,foo: { type: string, value: str: val: "asd" len: 3 is_ref: 1 refcount: 2 } bar: { //  bar     zval type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 1 }
      
      



 $qwe = $foo;
      
      



 zxc,foo: { type: string, value: str: val: "asd" len: 3 is_ref: 1 refcount: 2 } bar: { type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 1 } qwe: { //        zval type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 1 }
      
      







もちろん、fooから別のリンクを取得すると、fooによって参照されるzvalの参照カウントが1増加します。



おそらくそれだけです(今のところ?)、次のパートでは配列について説明します。



PS誰がこれらの写真を知覚するのかわかりません。面白いように思えました:)残念ながら、私はスキャナーを持っていません



All Articles