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

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

上記のセクションに続いて、PHP 拡張機能の配列とハッシュ テーブル API について説明します。このセクションでは主に について説明します。 コールバック走査関数、通常走査関数、デストラクタ、ソート、比較、極値関数

ハッシュによる反復適用: 配列を走査する最も簡単な方法は、PHP 言語の foreach ステートメントに似た関数 zend_hash_apply を使用することです。この関数はコールバック関数を受け取り、ハッシュテーブルの各要素をそれに渡します。

typedef int (*apply_func_t)(void *pDest TSRMLS_DC);
void zend_hash_apply(HashTable *ht,
        apply_func_t apply_func TSRMLS_DC);
ログイン後にコピー
typedef int (*apply_func_arg_t)(void *pDest,
                            void *argument TSRMLS_DC);
void <strong>zend_hash_apply_with_argument</strong>(HashTable *ht,
        apply_func_arg_t apply_func, void *data TSRMLS_DC);
ログイン後にコピー
1 つはパラメータを渡すことができ、もう 1 つはパラメータを渡さず、ハッシュ テーブル内の値のみを渡します。引数を渡すことができる関数の場合、拡張機能で適用できる可能性が高くなります。 コールバック関数は異なる戻り値を持つ場合があります。
コールバック関数のテーブル戻り値
一定の意味
ZEND_HASH_APPLY_KEEP は現在のリクエストを終了し、次のサイクルに入ります。これは、PHP 言語の forech ステートメントのループが実行された場合、または continue キーワードが検出された場合と同じ効果があります。
ZEND_HASH_APPLY_STOP が飛び出します。これは、PHP 言語の forech ステートメントの Break キーワードと同じ効果があります。
ZEND_HASH_APPLY_REMOVE は現在の要素を削除し、次の要素の処理を続行します。 PHP 言語の場合と同等: unset($foo[$key]);Continue;

単純なPHPトラバーサルコードの場合
<?php foreach($arr as $val) {     echo "The value is: $val\n"; }
?>
ログイン後にコピー
の拡張形式は次のとおりです。 まずコールバック関数を定義します 次に、
int php_sample_print_zval(zval **val TSRMLS_DC)
{
    //重新copy一个zval,防止破坏原数据
    zval tmpcopy = **val;
    zval_copy_ctor(&tmpcopy);
     
    //转换为字符串
    INIT_PZVAL(&tmpcopy);
    convert_to_string(&tmpcopy);
    
    //开始输出
    php_printf("The value is: ");
    PHPWRITE(Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy));
    php_printf("\n");
     
    //毁尸灭迹
    zval_dtor(&tmpcopy);
     
    //返回,继续遍历下一个~
    return ZEND_HASH_APPLY_KEEP;
}
ログイン後にコピー
はループ関数を定義します: zend_hash_apply(arrht, php_sample_print_zval TSRMLS_CC);
要素タイプが zval* である arrht という名前のハッシュ テーブルが走査されます。
ハッシュ テーブルに格納されるのは要素ではなく、ポインタ (zval**) であることに注意してください。コピーすると、ポインタもコピーされ、ハッシュ テーブル自体の内容は変更されません。

ループ中に値とキーの両方を受け取るために、zend_hash_apply() の 3 番目の形式: zend_hash_apply_with_arguments() この PHP コードに対する
<?php
foreach($arr as $key => $val) {     echo "The value of $key is: $val\n"; }
?>
ログイン後にコピー
の C コード: れーれー
トラバーサルを実行します。 zend_hash_apply_with_arguments(arrht, php_sample_print_zval_and_key, 0); hash_key が文字列型であるか数値型であるかを確認する場合、arKey 属性ではなく、nKeyLength 属性を通じて検出されます。これは、カーネルが arKey 属性にダーティ データを残すことがありますが、nKeyLength 属性は安全であり、安全に使用できるためです。空の文字列インデックスも処理できます。例: $foo[''] = "Bar"; インデックス値は NULL 文字ですが、その長さには最後の NULL 文字が含まれるため、1 になります。

前進による反復 ハッシュ テーブルのトラバーサルはコールバックなしで実装できます。このとき、ハッシュテーブルの内部ポインタが使用される。
ユーザー空間では多くの機能が利用可能です:
int php_sample_print_zval_and_key(zval **val,         int num_args, va_list args, zend_hash_key *hash_key) {
    /* 复制zval从而使得原来的内容被保存下来 */     
    zval tmpcopy = **val;     
    /* tsrm_ls is needed by output functions */     
    TSRMLS_FETCH();     
    zval_copy_ctor(&tmpcopy);     
    /* Reset refcount & Convert */
    INIT_PZVAL(&tmpcopy);
    convert_to_string(&tmpcopy);     
    /* 输出 */
    php_printf("The value of ");
    if (hash_key->nKeyLength) {  
        /* 如果是字符串类型的key */    
        PHPWRITE(hash_key->arKey, hash_key->nKeyLength);     
    } else {
        /* 如果是数字类型的key */ 
        php_printf("%ld", hash_key->h);     
    }
    php_printf(" is: ");
    PHPWRITE(Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy));     php_printf("\n");
    /* Toss out old copy */
    zval_dtor(&tmpcopy);
    /* continue; */
    return ZEND_HASH_APPLY_KEEP;
}
ログイン後にコピー
対応する各関数には zend バージョンがあります。
<?php
    $arr = array('a'=>1, 'b'=>2, 'c'=>3);
    reset($arr);
    while (list($key, $val) = each($arr)) {
        /* Do something with $key and $val */
    }
    reset($arr);
    $firstkey = key($arr);
    $firstval = current($arr);
    $bval = next($arr);
    $cval = next($arr);
?>
ログイン後にコピー
next() prev() end() は実際に対応するインデックス値を検索し、zend_hash_get_current_data() を使用して要素値を返します
each() は次のステップと同じですが、zend_hash_get_current_key() を呼び出して返します

したがって、コールバック関数を使用しないハッシュ テーブル トラバーサル メソッドを次に示します。
	* /* reset() */
void zend_hash_internal_pointer_reset(HashTable *ht);
        /* key() */
int zend_hash_get_current_key(HashTable *ht,
        char **strIdx, unit *strIdxLen,
        ulong *numIdx, zend_bool duplicate);
	* /* current() */
int zend_hash_get_current_data(HashTable *ht, void **pData);
	* /* next()/each() */
int zend_hash_move_forward(HashTable *ht);
	* /* prev() */
int zend_hash_move_backwards(HashTable *ht);
	* /* end() */
void zend_hash_internal_pointer_end(HashTable *ht);
	* /* Other... */
int zend_hash_get_current_key_type(HashTable *ht);
int zend_hash_has_more_elements(HashTable *ht);
ログイン後にコピー
zend_hash_get_current_key_ex 戻り値の可能性を見てみましょう。 一定の意味

HASH_KEY_IS_STRING 現在の要素のインデックスは文字列型です。したがって、要素のキー名へのポインタが strIdx に設定され、その長さが stdIdxLen に設定されます。重複フラグがゼロ以外の値に設定されている場合、キーは前に estrndup() されます。 呼び出し元のアプリケーションは、この重複した文字列を解放する必要があります。

HASH_KEY_IS_LONG 現在の要素のインデックスは数値です。
HASH_KEY_NON_EXISTANT HashTable の内部ポインターが末尾に移動され、どの要素も指していません。


破壊 デストラクターは 4 つだけであることに注意してください。 最初の 2 つは、ハッシュ テーブルから個々の要素を削除するために使用されます。
void php_sample_print_var_hash(HashTable *arrht)
{
    for(zend_hash_internal_pointer_reset(arrht);
    zend_hash_has_more_elements(arrht) == SUCCESS;
    zend_hash_move_forward(arrht)) {
        char *key;
        uint keylen;
        ulong idx;
        int type;
        zval **ppzval, tmpcopy;
        type = zend_hash_get_current_key_ex(arrht, &key, &keylen,
                                                  &idx, 0, NULL);//获得返回的key的类型。这个类型可能有三种
        if (zend_hash_get_current_data(arrht, (void**)&ppzval) == FAILURE) {//获得当前索引所指的数据值
            /* Should never actually fail
             * since the key is known to exist. */
            continue;
        }
        /* 复制zval的值,从而原来的值不会被破坏掉 */
        tmpcopy = **ppzval;
        zval_copy_ctor(&tmpcopy);
        /* 重新设定refcount 并且转换 */
        INIT_PZVAL(&tmpcopy);
        convert_to_string(&tmpcopy);
        /* 输出 */
        php_printf("The value of ");
        if (type == HASH_KEY_IS_STRING) {
            /* String Key / Associative */
            PHPWRITE(key, keylen);
        } else {
            /* Numeric Key */
            php_printf("%ld", idx);
        }
        php_printf(" is: ");
        PHPWRITE(Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy));
        php_printf("\n");
        /* 销毁原来的副本 */
        zval_dtor(&tmpcopy);
    }
}
ログイン後にコピー
は成功または失敗を返します
それぞれ文字列インデックスと数値インデックスに対応するバージョン。
要素がハッシュ テーブルから削除されると、要素へのポインタを使用してハッシュ テーブルのデストラクタが呼び出されます。

ハッシュ テーブルを完全に削除する場合: void zend_hash_clean(HashTable *ht); これは、ループ内で zend_hash_del を呼び出すのと同じです。 clean の実行に加えて、次の関数を呼び出すと、zend_hash_init によって適用されたすべてのスペースも破棄されます: void zend_hash_destroy(HashTable *ht);
プロセス全体をより明確に理解するために、ハッシュ テーブルのライフ サイクルを見てみましょう。 リーリー

分類、比較、そして極限への挑戦 2 つのハッシュ テーブルのサイズを比較するには: typedef int (*compare_func_t)(void *a, void *b TSRMLS_DC); この関数は qsort とまったく同じで、独自の関数が a と b を比較して -1 0 1 を返すことを期待しています

サイズ比較を使用した例を次に示します:
int zend_hash_del(HashTable *ht, char *arKey, uint nKeyLen);
int zend_hash_index_del(HashTable *ht, ulong h);
ログイン後にコピー
flag が 0 の場合は最小値が返され、それ以外の場合は最大値が返されます。

下面则给出一个更为具体的例子,通过不同的flag就可以控制到底是返回最大值还是最小值:
int fname_compare(zend_function *a, zend_function *b TSRMLS_DC)
{
    return strcasecmp(a->common.function_name, b->common.function_name);
}
void php_sample_funcname_sort(TSRMLS_D)
{
    zend_function *fe;
    if (zend_hash_minmax(EG(function_table), fname_compare,
                0, (void **)&fe) == SUCCESS) {
        php_printf("Min function: %s\n", fe->common.function_name);
    }
    if (zend_hash_minmax(EG(function_table), fname_compare,
                1, (void **)&fe) == SUCCESS) {
        php_printf("Max function: %s\n", fe->common.function_name);
    }
}
ログイン後にコピー

还有一个进行哈希比较的函数: int zend_hash_compare(HashTable *hta, HashTable *htb,
compare_func_t compar, zend_bool ordered TSRMLS_DC); 先比较哈希表的个数,哪个多哪个大。 如果一样多的,就每个元素去比较。

另外还有一个专门的排序函数:
typedef void (*sort_func_t)(void **Buckets, size_t numBuckets,
            size_t sizBucket, compare_func_t comp TSRMLS_DC);
int zend_hash_sort(HashTable *ht, sort_func_t sort_func,
        compare_func_t compare_func, int renumber TSRMLS_DC);
ログイン後にコピー
一般就用zend_qsort作为sort_func就够了。renumber这个参数如果设为1的话,那么就会抛弃原有的索引键值关系,赋予新的数字键值。 zend_hash_sort(target_hash, zend_qsort,array_data_compare, 1 TSRMLS_CC); array_data_compare是一个返回compare_func_t类型数据的函数,它将按照HashTable中zval*值的大小进行排序。


www.bkjia.comtruehttp://www.bkjia.com/PHPjc/635044.htmlTechArticle接着上面一节,继续说php扩展中的数组与哈希表的api,这节主要是说回调遍历函数正常遍历函数析构函数排序、对比、极函数 Iteration by ha...
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!