浅析PHP原理之变量分离/引用(Variables Separation)_php技巧
首先我们回顾一下zval的结构:
struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount;
zend_uchar type; /* active type */
zend_uchar is_ref;
};
其中的refcount和is_ref字段我们一直都没有介绍过,我们知道PHP是一个长时间运行的服务器端的脚本解释器。那么对于它来说,效率和资源占用率是一个很重要的衡量标准,也就是说,PHP必须尽量介绍内存占用率,考虑下面这段代码:
$var = "laruence";
$var_dup = $var;
unset($var);
?>
第一行代码创建了一个字符串变量,申请了一个大小为9字节的内存,保存了字符串”laruence”和一个NULL(/0)的结尾。
第二行定义了一个新的字符串变量,并将变量var的值”复制”给这个新的变量。
第三行unset了变量var
这样的代码在我们平时的脚本中是很常见的,如果PHP对于每一个变量赋值都重新分配内存,copy数据的话,那么上面的这段代码公要申请18个字节的内存空间,而我们也很容易的看出来,上面的代码其实根本没有必要申请俩份空间,呵呵,PHP的开发者也看出来了:
我们之前讲过,PHP中的变量是用一个存储在symbol_table中的符号名,对应一个zval来实现的,比如对于上面的第一行代码,会在symbol_table中存储一个值”var”, 对应的有一个指针指向一个zval结构,变量值”laruence”保存在这个zval中,所以不难想象,对于上面的代码来说,我们完全可以让”var”和”var_dup”对应的指针都指向同一个zval就可以了。
PHP也是这样做的,这个时候就需要介绍我们之前一直没有介绍过的zval结构中的refcount字段了。
refcount,顾名思义,记录了当前的zval被引用的计数。
比如对于代码:
$var = 1;
$var_dup = $var;
?>
第一行,创建了一个整形变量,变量值是1。 此时保存整形1的这个zval的refcount为1。
第二行,创建了一个新的整形变量,变量也指向刚才创建的zval,并将这个zval的refcount加1,此时这个zval的refcount为2。
PHP提供了一个函数可以帮助我们了解这个过程debug_zval_dump:
$var = 1;
debug_zval_dump($var);
$var_dup = $var;
debug_zval_dump($var);
?>
输出:
long(1) refcount(2)
long(1) refcount(3
如果你奇怪 ,var的refcount应该是1啊?
我们知道,对于简单变量,PHP是以传值的形式穿参数的。也就是说,当执行debug_zval_dump($var)的时候,$var会以传值的方式传递给debug_zval_dump,也就是会导致var的refcount加1,所以我们只要能看到,当变量赋值给一个变量以后,能导致zval的refcount加1这个事实即可。
现在我们回头看文章开头的代码, 当执行了最后一行unset($var)以后,会发生什么呢? 对,既是refcount减1,上代码:
$var = "laruence";
$var_dup = $var;
unset($var);
debug_zval_dump($var_dup);
?>
输出:
string(8) "laruence" refcount(2
但是,对于下面的代码呢?
$var = "laruence";
$var_dup = $var;
$var = 1;
?>
很明显在这段代码执行以后,$var_dup的值应该还是”laruence”, 那么这又是怎么实现的呢?
这就是PHP的copy on write机制:
PHP在修改一个变量以前,会首先查看这个变量的refcount,如果refcount大于1,PHP就会执行一个分离的例程, 对于上面的代码,当执行到第三行的时候,PHP发现$var指向的zval的refcount大于1,那么PHP就会复制一个新的zval出来,将原zval的refcount减1,并修改symbol_table,使得$var和$var_dup分离(Separation)。这个机制就是所谓的copy on write(写时复制)。
上代码测试:
$var = "laruence";
$var_dup = $var;
$var = 1;
debug_zval_dump($var);
debug_zval_dump($var_dup);
?>
输出:
long(1) refcount(2)
string(8) "laruence" refcount(2
现在我们知道,当使用变量复制的时候 ,PHP内部并不是真正的复制,而是采用指向相同的结构来尽量节约开销。那么,对于PHP中的引用,那又是如何实现呢?
$var = "laruence";
$var_ref = &$var;
$var_ref = 1;
?>
这段代码结束以后,$var也会被间接的修改为1,这个过程称作(change on write:写时改变)。那么ZE是怎么知道,这次的复制是不需要Separation的呢?
这个时候就要用到zval中的is_ref字段了:
对于上面的代码,当第二行执行以后,$var所代表的zval的refcount变为2,并且同时置is_ref为1。
到第三行的时候,PHP先检查var_ref代表的zval的is_ref字段,如果为1,则不分离,大体逻辑示意如下:
if((*val)->is_ref || (*val)->refcount //不执行Separation
... ;//process
}
但是,问题又来了,对于如下的代码,又会怎样呢?
$var = "laruence";
$var_dup = $var;
$var_ref = &$var;
?>
对于上面的代码,存在一对copy on write的变量$var和$var_dup, 又有一对change on write机制的变量对$var和$var_ref,这个情况又是如何运作的呢?
当第二行执行的时候,和前面讲过的一样,$var_dup 和 $var 指向相同的zval, refcount为2.
当执行第三行的时候,PHP发现要操作的zval的refcount大于1,则,PHP会执行Separation, 将$var_dup分离出去,并将$var和$var_ref做change on write关联。也就是,refcount=2, is_ref=1;
基于这样的分析,我们就可以让debug_zval_dump出refcount为1的结果来:
$var = "laruence";
$var_dup = &$var;
debug_zval_dump($var);
?>
输出:
string(8) "laruence" refcount(1
详细原因,读者你只要稍加分析就能得出,我就不越俎代庖了。;)
这次我们介绍了PHP的变量分离机制,下次我会继续介绍如果在扩展中接收和传出PHP脚本中的参数。

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Dalam iOS 17 dan macOS Sonoma, Apple telah menambah pilihan pemformatan baharu untuk Apple Notes, termasuk petikan blok dan gaya Monostyle baharu. Inilah cara untuk menggunakannya. Dengan pilihan pemformatan tambahan dalam Apple Notes, anda kini boleh menambah petikan blok pada nota anda. Format petikan blok memudahkan untuk mengimbangi bahagian penulisan secara visual menggunakan bar petikan di sebelah kiri teks. Hanya ketik/klik butang format "Aa" dan pilih pilihan petikan blok sebelum menaip atau apabila anda berada di baris yang anda ingin tukar kepada petikan blok. Pilihan ini digunakan pada semua jenis teks, pilihan gaya dan senarai, termasuk senarai semak. Dalam menu Format yang sama anda boleh mencari pilihan Gaya Tunggal baharu. Ini ialah semakan bagi "lebar sama" sebelumnya

Pembolehubah persekitaran ialah laluan ke lokasi (atau persekitaran) tempat aplikasi dan program dijalankan. Ia boleh dibuat, diedit, diurus atau dipadamkan oleh pengguna dan berguna apabila menguruskan tingkah laku proses tertentu. Berikut ialah cara untuk mencipta fail konfigurasi untuk mengurus berbilang pembolehubah secara serentak tanpa perlu mengeditnya secara individu pada Windows. Cara menggunakan profil dalam pembolehubah persekitaran Windows 11 dan 10 Pada Windows, terdapat dua set pembolehubah persekitaran – pembolehubah pengguna (digunakan untuk pengguna semasa) dan pembolehubah sistem (digunakan secara global). Walau bagaimanapun, menggunakan alat seperti PowerToys, anda boleh mencipta fail konfigurasi yang berasingan untuk menambah pembolehubah baharu dan sedia ada serta mengurus semuanya sekali gus. Begini caranya: Langkah 1: Pasang PowerToysPowerTo

C++ ialah bahasa pengaturcaraan yang popular, tetapi semasa penggunaan, ralat kompilasi "rujukan tidak ditentukan" sering berlaku, yang membawa banyak masalah kepada pembangunan program. Artikel ini akan membincangkan penyelesaian kepada ralat "rujukan tidak ditentukan" daripada punca dan penyelesaiannya. 1. Punca ralat Apabila pengkompil C++ menyusun fail sumber, ia akan dibahagikan kepada dua peringkat: peringkat penyusunan dan peringkat pautan. Fasa kompilasi menukarkan kod sumber dalam fail sumber kepada kod pemasangan, manakala fasa pemautan menggabungkan fail sumber yang berbeza menjadi fail boleh laku.

Mod ketat telah diperkenalkan dalam PHP7, yang boleh membantu pembangun mengurangkan kemungkinan ralat. Artikel ini akan menerangkan apa itu mod ketat dan cara menggunakan mod ketat dalam PHP7 untuk mengurangkan ralat. Pada masa yang sama, penggunaan mod ketat akan ditunjukkan melalui contoh kod. 1. Apakah mod ketat? Mod ketat ialah ciri dalam PHP7 yang boleh membantu pembangun menulis kod yang lebih standard dan mengurangkan beberapa ralat biasa. Dalam mod ketat, akan ada sekatan dan pengesanan yang ketat pada pengisytiharan berubah-ubah, pemeriksaan jenis, panggilan fungsi, dsb. lulus

Pembolehubah contoh dalam Java merujuk kepada pembolehubah yang ditakrifkan dalam kelas, bukan dalam kaedah atau pembina. Pembolehubah contoh juga dipanggil pembolehubah ahli Setiap contoh kelas mempunyai salinan pembolehubah contoh sendiri. Pembolehubah contoh dimulakan semasa penciptaan objek, dan keadaannya disimpan dan dikekalkan sepanjang hayat objek. Takrif pembolehubah contoh biasanya diletakkan di bahagian atas kelas dan boleh diisytiharkan dengan mana-mana pengubah suai akses, yang boleh menjadi umum, peribadi, dilindungi atau pengubah akses lalai. Ia bergantung kepada apa yang kita mahu ini

Menggunakan Ajax untuk mendapatkan pembolehubah daripada kaedah PHP adalah senario biasa dalam pembangunan web Melalui Ajax, halaman boleh diperoleh secara dinamik tanpa menyegarkan data. Dalam artikel ini, kami akan memperkenalkan cara menggunakan Ajax untuk mendapatkan pembolehubah daripada kaedah PHP, dan memberikan contoh kod khusus. Pertama, kita perlu menulis fail PHP untuk mengendalikan permintaan Ajax dan mengembalikan pembolehubah yang diperlukan. Berikut ialah kod contoh untuk fail PHP mudah getData.php:

Faedah fungsi mengembalikan jenis rujukan dalam C++ termasuk: Peningkatan prestasi: Melewati rujukan mengelakkan penyalinan objek, sekali gus menjimatkan memori dan masa. Pengubahsuaian langsung: Pemanggil boleh mengubah suai secara langsung objek rujukan yang dikembalikan tanpa menugaskannya semula. Kesederhanaan kod: Lulus melalui rujukan memudahkan kod dan tidak memerlukan operasi penugasan tambahan.

Python digunakan secara meluas dalam pelbagai bidang dengan sintaksnya yang ringkas dan mudah dibaca. Menguasai struktur asas sintaks Python adalah penting, kedua-duanya untuk meningkatkan kecekapan pengaturcaraan dan untuk mendapatkan pemahaman yang mendalam tentang cara kod tersebut berfungsi. Untuk tujuan ini, artikel ini menyediakan peta minda komprehensif yang memperincikan pelbagai aspek sintaks Python. Pembolehubah dan Jenis Data Pembolehubah ialah bekas yang digunakan untuk menyimpan data dalam Python. Peta minda menunjukkan jenis data Python biasa, termasuk integer, nombor titik terapung, rentetan, nilai Boolean dan senarai. Setiap jenis data mempunyai ciri dan kaedah operasinya sendiri. Operator Operator digunakan untuk melaksanakan pelbagai operasi pada jenis data. Peta minda merangkumi jenis operator yang berbeza dalam Python, seperti operator aritmetik, nisbah
