Rumah php教程 php手册 php的扩展和嵌入--php内部变量

php的扩展和嵌入--php内部变量

Jun 13, 2016 am 10:19 AM
dalaman Benamkan Kembangkan

之前对于php的内部生命周期和Zend引擎的线程安全机制做了一个介绍,这里这篇文章则是主要介绍php的内部变量是如何实现的。

了解了这些实现的方法之后,对于写php,尤其是进行php扩展开发感觉相当有帮助。


php是一种类型比较松散的语言,与C相比不需要在使用变量前给出类型,直接用就可以。为了实现这一点,php必须在数据类型的定义上做一些工作。

数据类型:

最基本的类型被称为是zval或者说Zend Value,定义在Zend/zend.h头文件中。 typedef struct _zval_struct {
zvalue_value value;
zend_uint refcount;
zend_uchar type;
zend_uchar is_ref;
} zval; 其中zvalue_value按照如下定义: typedef union _zvalue_value {
long lval;
double dval;
struct {
char *val;
int len;
} str;
HashTable *ht;
zend_object_value obj;
} zvalue_value; 这个是一个union,使用union的时候两种可能,一种是所有的变量共享一片内存空间,一种是要对其中的类型进行n选1的时候。
Zend定义了8种基本的数据类型,这八种基本上在别的语言中也都见过,所以只对比较特殊的类型进行说明: IS_NULL:non-valueIS_BOOL:IS_LONGIS_DOUBLEIS_STRING:分配的空间需要是长度+1IS_ARRAY: php的数组其实是hashtable,其中包括label和dataIS_OBJECT:在数组的基础上加上了 方法、访问修改符、有域的常量以及特殊的事件处理器IS_RESOURCE:比如文件的句柄或是mysql的句柄这些存储在zval的type中,并且与zvalue_value有着分别的对应关系 注意下面有两个类型判断函数的对比:
void describe_zval(zval *foo)
{
    if (foo->type == IS_NULL) {
        php_printf("The variable is NULL");
    } else {
        php_printf("The variable is of type %d", foo->type);
    }
}
Salin selepas log masuk
void describe_zval(zval *foo)
{
    if (Z_TYPE_P(foo) == IS_NULL) {
        php_printf("The variable is NULL");
    } else {
        php_printf("The variable is of type %d",
                            Z_TYPE_P(foo));
    }
}
Salin selepas log masuk

第一段代码中采用的是c的写法,第二段代码是带有php特色的写法。 注意到Zend头文件中提供了很多对zval处理的宏,最好用它们,这里就是用了Z_TYPE_P(foo)。同样还有Z_TYPE()和Z_TYPE_PP()分别对应zval和zval** php_printf()则是在printf的基础上做了些针对SAPI和php输出机制的优化。


数据值

通过一些宏可以获取不同类型的zval的值: BVAL(): BooleanLVAL(): longDVAL(): double 这个函数针对三种不同的zval类型,分别利用Z_TYPE进行了类型判断。然后利用相应的值提取的宏进行取值。
void display_values(zval boolzv, zval *longpzv,
               zval **doubleppzv)
{
    if (Z_TYPE(boolzv) == IS_BOOL) {
        php_printf("The value of the boolean is: %s\n",
            Z_BVAL(boolzv) ? "true" : "false");
    }
    if (Z_TYPE_P(longpzv) == IS_LONG) {
        php_printf("The value of the long is: %ld\n",
            Z_LVAL_P(longpzv));
    }
    if (Z_TYPE_PP(doubleppzv) == IS_DOUBLE) {
        php_printf("The value of the double is: %f\n",
            Z_DVAL_PP(doubleppzv));
    }
}
Salin selepas log masuk

对于string的处理则要稍微特殊一些:需要两个宏Z_STRVAZ_STRLEN分别读取值和长度,这个从string类型的定义中也可以看到,它是由字符和长度组成的。
void display_string(zval *zstr)
{
    if (Z_TYPE_P(zstr) != IS_STRING) {
        php_printf("The wrong datatype was passed!\n");
        return;
    }
    PHPWRITE(Z_STRVAL_P(zstr), Z_STRLEN_P(zstr));
}
Salin selepas log masuk

对数组的访问使用的是ARRVAL系列:Z_ARRVAL(zv), Z_ARRVAL_P(pzv), Z_ARRVAL_PP(ppzv). 有一些版本的php源码中HASH_OF()等同于Z_ARRVAL_P,但是这个宏已经渐渐的用的少了.
对于Object: OBJ_HANDLE 返回对象句柄标识OBJ_HT 句柄表OBJCE 类定义OBJPROP 属性哈希表OBJ_HANDLER 在OBJ_HT中操作特定处理方法 对于资源Resource就直接用宏RESVAL

数据创建:

想要创造一个变量并分配空间的malloc(sizeof(zval))在php这里并不可行。应该使用MAKE_STD_ZVAL(pzv), 它对空间的分配进行了优化,并且会自动的初始化refCount(表示这个变量被引用的次数)和is_ref(是否是强制引用)这两个性质。注意它的输入是一个指针.
ALLOC_INIT_ZVAL()也可以进行初始化,不同之处在于把zval*的值设为了NULL.
在设置不同类型的值的时候有很多形式,左边是比较简略的形式,右侧则是展开的形式: ZVAL_NULL(pvz); Z_TYPE_P(pzv) = IS_NULL;
ZVAL_BOOL(pzv, b); Z_TYPE_P(pzv) = IS_BOOL;
Z_BVAL_P(pzv) = b ? 1 : 0;
ZVAL_TRUE(pzv); ZVAL_BOOL(pzv, 1);
ZVAL_FALSE(pzv); ZVAL_BOOL(pzv, 0);
ZVAL_LONG(pzv, l); Z_TYPE_P(pzv) = IS_LONG;
Z_LVAL_P(pzv) = l;
ZVAL_DOUBLE(pzv, d); Z_TYPE_P(pzv) = IS_DOUBLE;
Z_DVAL_P(pzv) = d;
对于字符串的处理要特殊一些,提供了一个单独的参数dup. 这个参数决定了是否创建一个字符串的副本.举个例子 zval * pzva; ZVAL_STRING(pzval,"hello world",1); 由于“hello_world”是一个常量字符串,直接对它进行操作显然不合适,所以把dup设为1的话,会自动的给它创建一个副本,然后再赋给pzval. 这使得整个过程更加简洁。

ZVAL_STRINGL(pzv,str,len,dup); Z_TYPE_P(pzv) = IS_STRING;
Z_STRLEN_P(pzv) = len;
if (dup) {
Z_STRVAL_P(pzv) =
estrndup(str, len + 1);
} else {
Z_STRVAL_P(pzv) = str;
}
ZVAL_STRING(pzv, str, dup); ZVAL _STRINGL(pzv, str,
strlen(str), dup); 注意dup如果设为1的话就是申请新的空间并且拷贝内容,而不是一个shaddow copy。 ZVAL_RESOURCE(pzv, res); Z_TYPE_P(pzv) = IS_RESOURCE;
Z_RESVAL_P(pzv) = res;


数据的存储

数据的存储都在符号表中。 symbol table,每当创建一个新的变量的时候,Zend都保存这个值到这个内部的数组中去。 符号表在RINIT之前创建,在RSHUTDOWN之后销毁。
当用户空间的函数或对象方法被调用的时候,会创建一个新的符号表,生命与函数执行时间相同。 在Zend/zend_gblobals.h中定义了两个元素:
struct _zend_executor_globals {
    ...
    HashTable symbol_table;
    HashTable *active_symbol_table;
    ...
};
Salin selepas log masuk

通过EG(symbol_table) 的方式可以访问符号表。感觉跟$GLOBALS似的。 注意到EG(symbol_table)这个宏返回的不是指针,必须加上&。 下面的这个对比非常的有趣: In PHP:
<?php $foo = 'bar'; ?>
Salin selepas log masuk
针对这段php的代码,C中一共做了如下这些事:
In C:
{
    zval *fooval;
    MAKE_STD_ZVAL(fooval); //首先分配空间,设置变量
    ZVAL_STRING(fooval, "bar", 1); //然后赋值,创建一个copy,你不能直接操作常字符串
    ZEND_SET_SYMBOL(EG(active_symbol_table), "foo", fooval); // 在符号表中注册,foo是一个label
}
Salin selepas log masuk
所谓active_symbol_table指的是程序执行当前的符号表,在进入一个函数之后,会有它自己对应的符号表,就类似于C中针对一个函数自己的栈空间。而当退出了函数之后,它的符号表会被销毁,这时候又回到了下面这个状态: EG(active_symbol_table) == &EG(symbol_table), 这个时候并没有进入函数。

数据的获取: 在获取数据的时候,比较多的是使用zend_hash_find()函数:

{
    zval **fooval;
    if (zend_hash_find(EG(active_symbol_table),
                       "foo", sizeof("foo"),
                       (void**)&fooval) == SUCCESS) {
        php_printf("Got the value of $foo!");
    } else {
        php_printf("$foo is not defined.");
    }
}
Salin selepas log masuk
这个函数首先查找符号表,找到名字为“foo”的变量,然后返回到fooval中。下面着重解释两个问题:

为什么要声明一个zval ** fooval 然后还要通过&fooval并且转换为(void **)的形式?为什么要用sizeof("foo") 对第一个问题,要考虑到我们寻找的目标是一个zval*,所以要把它看作一个整体。利用这种写法可以避免编译告警。 第二个问题,使用sizeof(label)主要是为了表示字符串常量label的尾部,这里使用4也是可以的,但是通用性不够。

数据转换: 仅仅是说一下有这个功能,比如convert_to_string(zval *value)可以把zval转换为字符串。


以上就是php内部变量的一些介绍,为了能够区分不同的类型、设置获取变量值以及在符号表中增加和查找变量,这些知识必不可少。




Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Bagaimana untuk menggunakan sambungan SNMP PHP? Bagaimana untuk menggunakan sambungan SNMP PHP? Jun 02, 2023 am 10:22 AM

Sambungan SNMP untuk PHP ialah sambungan yang membolehkan PHP berkomunikasi dengan peranti rangkaian melalui protokol SNMP. Menggunakan sambungan ini, anda boleh mendapatkan dan mengubah suai maklumat konfigurasi peranti rangkaian dengan mudah, seperti CPU, memori, antara muka rangkaian dan maklumat lain penghala, suis, dsb. Anda juga boleh melakukan operasi kawalan seperti menukar port peranti. Artikel ini akan memperkenalkan pengetahuan asas protokol SNMP, cara memasang sambungan SNMP PHP dan cara menggunakan sambungan SNMP dalam PHP untuk memantau dan mengawal peranti rangkaian. 1. SN

Menggabungkan PHP dengan HTML: tiga teknik untuk membenamkan kod Menggabungkan PHP dengan HTML: tiga teknik untuk membenamkan kod Mar 06, 2024 am 08:09 AM

Gabungan PHP dan HTML ialah teknologi biasa dalam pembangunan web PHP boleh membenamkan kandungan dinamik dalam fail HTML dan melaksanakan fungsi tambahan, yang sangat meningkatkan interaktiviti dan kebolehubahsuaian laman web. Artikel ini akan memperkenalkan tiga teknik untuk membenamkan kod dan menyediakan contoh kod khusus untuk rujukan. 1. Gunakan tag PHP untuk membenamkan kod Cara yang paling biasa ialah menggunakan tag PHP () untuk membenamkan kod PHP ke dalam fail HTML untuk memaparkan kandungan dinamik. Sebagai contoh, anda boleh menggunakan PHP

Dari awal hingga akhir: Cara menggunakan cURL sambungan php untuk membuat permintaan HTTP Dari awal hingga akhir: Cara menggunakan cURL sambungan php untuk membuat permintaan HTTP Jul 29, 2023 pm 05:07 PM

Dari awal hingga akhir: Cara menggunakan cURL sambungan php untuk permintaan HTTP Pengenalan: Dalam pembangunan web, selalunya perlu untuk berkomunikasi dengan API pihak ketiga atau pelayan jauh lain. Menggunakan cURL untuk membuat permintaan HTTP ialah cara yang biasa dan berkesan. Artikel ini akan memperkenalkan cara menggunakan PHP untuk melanjutkan cURL untuk melaksanakan permintaan HTTP dan menyediakan beberapa contoh kod praktikal. 1. Penyediaan Pertama, pastikan php telah memasang sambungan cURL. Anda boleh melaksanakan php-m|grepcurl pada baris arahan untuk menyemak

Sambungan dan modul pihak ketiga untuk fungsi PHP Sambungan dan modul pihak ketiga untuk fungsi PHP Apr 13, 2024 pm 02:12 PM

Untuk melanjutkan fungsi fungsi PHP, anda boleh menggunakan sambungan dan modul pihak ketiga. Sambungan menyediakan fungsi dan kelas tambahan yang boleh dipasang dan didayakan melalui pengurus pakej pecl. Modul pihak ketiga menyediakan fungsi khusus dan boleh dipasang melalui pengurus pakej Komposer. Contoh praktikal termasuk menggunakan sambungan untuk menghuraikan data JSON yang kompleks dan menggunakan modul untuk mengesahkan data.

Bagaimana untuk memasang sambungan mbstring di bawah CENTOS7? Bagaimana untuk memasang sambungan mbstring di bawah CENTOS7? Jan 06, 2024 pm 09:59 PM

1.UncaughtError:Calltoundefinedfunctionmb_strlen(); Apabila ralat di atas berlaku, ini bermakna kami belum memasang sambungan mbstring 2. Masukkan direktori pemasangan PHP cd/temp001/php-7.1.0/ext/mbstring 3. Mulakan phpize(; /usr/local/bin /phpize atau /usr/local/php7-abel001/bin/phpize) arahan untuk memasang sambungan php 4../configure--with-php-config=/usr/local/php7-abel

Cara menggunakan sambungan Aurora Push untuk melaksanakan fungsi push mesej kelompok dalam aplikasi PHP Cara menggunakan sambungan Aurora Push untuk melaksanakan fungsi push mesej kelompok dalam aplikasi PHP Jul 25, 2023 pm 08:07 PM

Cara menggunakan sambungan Aurora Push untuk melaksanakan fungsi push mesej kelompok dalam aplikasi PHP Dalam pembangunan aplikasi mudah alih, mesej push adalah fungsi yang sangat penting. Jiguang Push ialah perkhidmatan tolak mesej yang biasa digunakan yang menyediakan fungsi dan antara muka yang kaya. Artikel ini akan memperkenalkan cara menggunakan sambungan Aurora Push untuk melaksanakan fungsi push mesej kelompok dalam aplikasi PHP. Langkah 1: Daftar akaun Jiguang Push dan dapatkan kunci API Pertama, kita perlu mendaftar di tapak web rasmi Jiguang Push (https://www.jiguang.cn/push).

Bagaimana untuk menggunakan sambungan ZipArchive PHP? Bagaimana untuk menggunakan sambungan ZipArchive PHP? Jun 02, 2023 am 08:13 AM

PHP ialah bahasa sebelah pelayan yang popular yang boleh digunakan untuk membangunkan aplikasi web dan memproses fail. Sambungan ZipArchive untuk PHP ialah alat yang berkuasa untuk memanipulasi fail zip dalam PHP. Dalam artikel ini, kami akan membincangkan cara menggunakan sambungan ZipArchive PHP untuk membuat, membaca dan mengubah suai fail zip. 1. Pasang sambungan ZipArchive Sebelum menggunakan sambungan ZipArchive, anda perlu memastikan sambungan telah dipasang. Kaedah pemasangan adalah seperti berikut: 1. Pasang

Bagaimana untuk menggunakan sambungan POSIX PHP? Bagaimana untuk menggunakan sambungan POSIX PHP? Jun 03, 2023 am 08:01 AM

Sambungan POSIX untuk PHP ialah satu set fungsi dan pemalar yang membolehkan PHP berinteraksi dengan sistem pengendalian yang mematuhi POSIX. POSIX (PortableOperatingSystemInterface) ialah satu set piawaian antara muka sistem pengendalian yang direka untuk membolehkan pembangun perisian menulis aplikasi yang boleh dijalankan pada pelbagai sistem pengendalian seperti UNIX atau UNIX. Artikel ini akan memperkenalkan cara menggunakan sambungan POSIX untuk PHP, termasuk pemasangan dan penggunaan. 1. Pasang sambungan POSIX PHP dalam

See all articles