ホームページ > バックエンド開発 > PHPチュートリアル > PHP 拡張機能と埋め込み -- PHP 拡張機能の配列とハッシュ テーブル 1_PHP チュートリアル

PHP 拡張機能と埋め込み -- PHP 拡張機能の配列とハッシュ テーブル 1_PHP チュートリアル

WBOY
リリース: 2016-07-13 10:42:26
オリジナル
1235 人が閲覧しました

PHP では、配列の基礎となる実装はハッシュ テーブルであり、キーと値の形式で表示されます。 PHP の Zend エンジンには、さまざまなハッシュ テーブル操作のためのハッシュ テーブルを操作するための特別な API があります。


創造

ハッシュテーブルの場合、初期化方法は毎回同じであり、次の関数zend_hash_initによって完了します:

int zend_hash_init(HashTable *ht, uint nSize,
    hash_func_t pHashFunction,
    dtor_func_t pDestructor, zend_bool persistent)
ログイン後にコピー
ここで、ht はハッシュ テーブルへのポインタであり、既存のハッシュテーブル変数を参照できます。新しいハッシュテーブルのメモリを申請することもできます。一般的な方法は次のとおりです:

ALLOC_HASHTABLE(ht)、ht = emalloc(sizeof(HashTable)); と同等。

nSizeは、事前にメモリに適用されると考えられるハッシュテーブルの最大要素数です。 2 の指数倍数でない場合は、nSize = pow(2, ceil(log(nSize, 2))) の式に従って増加します。たとえば、5 が与えられた場合、8 まで増加します。これは、メモリ管理の比較のためのものである必要があります。 便利なメカニズムが採用されています。

pHashFunction は以前のバージョンの zend eigine 関数に属しており、新しいバージョンでは常に NULL に設定できます。

pDestructor は、ハッシュ テーブル内の要素が削除されたときに呼び出されるメソッド (zend_hash_del() zend_hash_update()) の入り口を指します。これは、対応するコールバック関数です。 Method_name 関数が指定されている場合、関数が実装されるとき:

void メソッド名(void *pElement)
pElement は削除された要素を指します

persistent は、永続的なハッシュ テーブルであるかどうかを示すフラグです。永続データはリクエストから独立しており、RSHUTDOWN 中にログアウトされません。ただし、1 に設定すると、ht はメモリを適用するときに pemalloc() を使用する必要があります。

例: 各 PHP リクエスト ライフ サイクルでsymbol_table を初期化すると、zend_hash_init(&EG(symbol_table), 50, NULL, ZVAL_PTR_DTOR, 0); が表示されます。 設定を解除すると、ハッシュ テーブルに格納されている対応する zval* が zval_ptr_dtor() に送信されて破棄されます。


人口:
ハッシュ テーブルにデータを挿入および更新するための主な関数は 4 つあります:

int zend_hash_add(HashTable *ht, char *arKey, uint nKeyLen,
                void *pData, uint nDataSize, void **pDest);
int zend_hash_update(HashTable *ht, char *arKey, uint nKeyLen,
                void *pData, uint nDataSize, void **pDest);
int zend_hash_index_update(HashTable *ht, ulong h,
                void *pData, uint nDataSize, void **pDest);
int zend_hash_next_index_insert(HashTable *ht,
                void *pData, uint nDataSize, void **pDest);
ログイン後にコピー
最初の 2 つの関数は、php の $foo['bar'] = 'barvalue' などの文字列インデックスを持つデータをハッシュテーブルに追加し、その後拡張子に追加します。

zend_hash_add(fooHashTbl, "bar", sizeof("bar"), &barZval, sizeof(zval*), NULL);

対応するキー値と対応するテーブル値がハッシュテーブルに追加されます。

追加と更新の唯一の違いは、キーがすでに存在する場合、追加は失敗することです。

最後の 2 つの関数は、ht に数値インデックス データを追加することです。

zend_hash_next_index_insert() 関数はインデックス値パラメーターを必要としませんが、次の数値インデックス値をそれ自体で直接計算します。

次の要素の数値インデックス値を自分で取得したい場合は、zend_hash_next_free_element() を通じてインデックスを取得することもできます。

ulong nextid = zend_hash_next_free_element(ht);

zend_hash_index_update(ht, nextid, &data, sizeof(data), NULL);
上記のコードは次と同等です:

zend_hash_next_index_insert(HashTable *ht, &data,sizeof(data),NULL).

pDest パラメータは、新しく追加された要素のアドレス値を保存するために使用できます。



思い出してください:

を見つけてください 一般的に、ハッシュ テーブル内のデータを取得するには 2 つの方法があります:

りー

これは、以下の例でより明確に見ることができます:


int zend_hash_find(HashTable *ht, char *arKey, uint nKeyLength,
                                        void **pData);
int zend_hash_index_find(HashTable *ht, ulong h, void **pData);
ログイン後にコピー
ハッシュ テーブルの値を取得することに加えて、いくつかの要素の存在を知ることがより重要な場合もあります:

int zend_hash_exists(HashTable *ht, char *arKey, uint nKeyLen);
int zend_hash_index_exists(HashTable *ht, ulong h);
ログイン後にコピー
分别针对字符串索引和数字的索引。返回的是1和0.
if (zend_hash_exists(EG(active_symbol_table),
                                "foo", sizeof("foo"))) {//确定活动的符号表中是否存在foo变量
    /* $foo is set */
} else {
    /* $foo does not exist */
}
ログイン後にコピー


Quick Population and Recall 当需要对同一个字符串的key进行许多操作的时候比如先检测有没有,然后插入再修改之类的,可以使用zend_get_hash_value来进行提速。这个函数的返回值可以和quick系列的函数使用,从而达到加速的目的。因为不需要再重复计算字符串的散列值,而是直接使用已有的散列值
ulong zend_get_hash_value(char *arKey, uint nKeyLen);
ログイン後にコピー
用这个返回值传给下面的quick系列函数就可以达到加速的目的:
int zend_hash_quick_add(HashTable *ht,
    char *arKey, uint nKeyLen, ulong hashval,
    void *pData, uint nDataSize, void **pDest);
int zend_hash_quick_update(HashTable *ht,
    char *arKey, uint nKeyLen, ulong hashval,
    void *pData, uint nDataSize, void **pDest);
int zend_hash_quick_find(HashTable *ht,
    char *arKey, uint nKeyLen, ulong hashval, void **pData);
int zend_hash_quick_exists(HashTable *ht,
    char *arKey, uint nKeyLen, ulong hashval);
ログイン後にコピー

下面给出了一个在两个哈希表之间进行数据拷贝的例子:
void php_sample_hash_copy(HashTable *hta, HashTable *htb,
                    char *arKey, uint nKeyLen TSRMLS_DC)
{
    ulong hashval = zend_get_hash_value(arKey, nKeyLen);//获得用来加速的散列值hashval
    zval **copyval;
    if (zend_hash_quick_find(hta, arKey, nKeyLen,
                hashval, (void**)©val) == FAILURE) {//首先要在hta table里面找到相应的元素,并且存储在copyval中。
        /* arKey doesn't actually exist */
        return;
    }
    /* The zval* is about to be owned by another hash table */
    (*copyval)->refcount__gc++;//相应zval*变量的引用次数+1
    zend_hash_quick_update(htb, arKey, nKeyLen, hashval,
                copyval, sizeof(zval*), NULL);//把从hta中拿来的copyval放在htb里面。
}
ログイン後にコピー

注意并没有zend_hash_del函数。

Copy and Merging 有三个方法可以进行数据的拷贝,先来看第一个:
typedef void (*copy_ctor_func_t)(void *pElement);
void zend_hash_copy(HashTable *target, HashTable *source,
            copy_ctor_func_t pCopyConstructor,
            void *tmp, uint size);
ログイン後にコピー
在source中的每个元素都会被拷贝到target中.通过pCopyConstructor的处理可以使得在拷贝变量的时候对这些变量的ref_count进行加一的操作。target中原有的与source中索引位置相同的元素会被替换掉,而其他的元素则会被保留。
tmp这里放NULL,低版本才会用到。
size的话代表每个元素的大小,一般是sizeof(zval *)。
void zend_hash_merge(HashTable *target, HashTable *source,
            copy_ctor_func_t pCopyConstructor,
            void *tmp, uint size, int overwrite);
ログイン後にコピー
主要是多了一个overwrite的参数,如果非0,那就跟copy一样,如果是0,那就对于已经存在的元素就不会进行复制了。

下面的这一组函数允许使用一个归并的检查进行选择性的复制:
typedef zend_bool (*merge_checker_func_t)(HashTable *target_ht,
    void *source_data, zend_hash_key *hash_key, void *pParam);
void zend_hash_merge_ex(HashTable *target, HashTable *source,
            copy_ctor_func_t pCopyConstructor, uint size,
            merge_checker_func_t pMergeSource, void *pParam);
ログイン後にコピー
pMergeSource回调函数使得可以选择性的进行合并,而不是全部合并,这个给人的感觉有点像c语言里面快速排序函数所留的函数入口,可以决定排序的方式。
下面给出了一个应用的例子:
zend_bool associative_only(HashTable *ht, void *pData,
            zend_hash_key *hash_key, void *pParam)
{
    /* True if there's a key, false if there's not */
    return (hash_key->arKey && hash_key->nKeyLength);//字符串类型的key,因为存在nKeyLength
}
void merge_associative(HashTable *target, HashTable *source)
{
    zend_hash_merge_ex(target, source, zval_add_ref,
                sizeof(zval*), associative_only, NULL);
}
ログイン後にコピー





















www.bkjia.comtruehttp://www.bkjia.com/PHPjc/635039.htmlTechArticle在php中,数组的底层实现就是哈希表,都是以key-value的形式出现的。在php的Zend引擎中,针对不同的哈希表操作,都有着专门的对哈希表进行...
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート