php的扩展和嵌入--php内部变量
之前对于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); } }
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)); } }
第一段代码中采用的是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)); } }
对于string的处理则要稍微特殊一些:需要两个宏Z_STRVA和Z_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)); }
对数组的访问使用的是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; ... };
通过EG(symbol_table) 的方式可以访问符号表。感觉跟$GLOBALS似的。 注意到EG(symbol_table)这个宏返回的不是指针,必须加上&。 下面的这个对比非常的有趣: In PHP:
<?php $foo = 'bar'; ?>
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 }
数据的获取: 在获取数据的时候,比较多的是使用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."); } }
数据转换: 仅仅是说一下有这个功能,比如convert_to_string(zval *value)可以把zval转换为字符串。
以上就是php内部变量的一些介绍,为了能够区分不同的类型、设置获取变量值以及在符号表中增加和查找变量,这些知识必不可少。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











PHP の SNMP 拡張機能は、PHP が SNMP プロトコルを介してネットワーク デバイスと通信できるようにする拡張機能です。この拡張機能を使用すると、CPU、メモリ、ネットワークインターフェイスなどのネットワークデバイスの構成情報やルータ、スイッチなどの情報を簡単に取得および変更できます。また、スイッチングデバイスのポートなどの制御操作も実行できます。この記事では、SNMP プロトコルの基本知識、PHP の SNMP 拡張機能をインストールする方法、PHP で SNMP 拡張機能を使用してネットワーク デバイスを監視および制御する方法を紹介します。 1.SN

最初から最後まで: HTTP リクエストに php 拡張機能 cURL を使用する方法 はじめに: Web 開発では、多くの場合、サードパーティ API または他のリモート サーバーと通信する必要があります。 cURL を使用して HTTP リクエストを行うのは、一般的で強力な方法です。この記事では、PHP を使用して cURL を拡張して HTTP リクエストを実行する方法を紹介し、いくつかの実用的なコード例を示します。 1. 準備 まず、php に cURL 拡張機能がインストールされていることを確認します。コマンドラインで php-m|grepcurl を実行して確認できます。

PHP と HTML の組み合わせは、Web 開発における一般的なテクノロジです。PHP は、HTML ファイルに動的コンテンツを埋め込み、補助機能を実装することで、Web サイトの対話性とカスタマイズ性を大幅に向上させることができます。この記事では、コードを埋め込むための 3 つのテクニックを紹介し、参考として具体的なコード例を示します。 1. PHP タグを使用してコードを埋め込む 最も一般的な方法は、PHP タグ () を使用して PHP コードを HTML ファイルに埋め込み、動的コンテンツを表示することです。たとえば、PHP を使用できます。

PHP 関数の機能を拡張するには、拡張機能とサードパーティのモジュールを使用できます。拡張機能は、pecl パッケージ マネージャーを通じてインストールおよび有効化できる追加の関数とクラスを提供します。サードパーティ モジュールは特定の機能を提供し、Composer パッケージ マネージャーを通じてインストールできます。実際の例には、拡張機能を使用して複雑な JSON データを解析したり、モジュールを使用してデータを検証したりすることが含まれます。

1.UncaughtError:Calltoundependentfunctionmb_strlen(); 上記のエラーが発生した場合、mbstring 拡張機能がインストールされていないことを意味します; 2. PHP インストール ディレクトリ cd/temp001/php-7.1.0/ext/mbstring に入ります 3. phpize( /usr/local/bin /phpize または /usr/local/php7-abel001/bin/phpize) コマンドを使用して、php 拡張機能 4../configure--with-php-config=/usr/local/php7-abel をインストールします。

PHP の POSIX 拡張機能は、PHP が POSIX 準拠のオペレーティング システムと対話できるようにする関数と定数のセットです。 POSIX (PortableOperatingSystemInterface) は、ソフトウェア開発者がさまざまな UNIX または UNIX 類似のオペレーティング システム上で実行できるアプリケーションを作成できるように設計された一連のオペレーティング システム インターフェイス標準です。この記事では、PHP 用の POSIX 拡張機能のインストールと使用方法を紹介します。 1. PHP の POSIX 拡張機能を次の場所にインストールします。

PHP は、Web アプリケーションの開発やファイルの処理に使用できる人気のあるサーバー側言語です。 PHP 用の ZipArchive 拡張機能は、PHP で zip ファイルを操作するための強力なツールです。この記事では、PHP の ZipArchive 拡張機能を使用して zip ファイルを作成、読み取り、変更する方法について説明します。 1. ZipArchive 拡張機能をインストールする ZipArchive 拡張機能を使用する前に、拡張機能がインストールされていることを確認する必要があります。インストール方法は以下のとおりです。 1. インストールします。

PHP および WebDriver 拡張機能: ユーザーのクリックと入力操作をシミュレートする方法 近年、Web アプリケーションの急速な発展に伴い、自動テストの重要性がますます高まっています。自動テストでは、ユーザー操作のシミュレーションが重要なリンクであり、これによりアプリケーションをより正確にテストおよび検証できるようになります。 PHP 開発では、通常、SeleniumWebDriver を使用して自動テストを実装します。 SeleniumWebDriver は、シミュレートできる強力なツールです。
