PHP 拡張機能と埋め込み -- PHP 拡張機能の配列とハッシュ テーブル 2_PHP チュートリアル
Jul 13, 2016 am 10:42 AM
埋め込む
拡大する
上記のセクションに続いて、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);
ログイン後にコピー
コールバック関数のテーブル戻り値
一定の意味
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; }
ログイン後にコピー
要素タイプが 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"; } ?>
ログイン後にコピー
トラバーサルを実行します。 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; }
ログイン後にコピー
<?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); ?>
ログイン後にコピー
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);
ログイン後にコピー
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就可以控制到底是返回最大值还是最小值:
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);
ログイン後にコピー
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

人気の記事
レポ:チームメイトを復活させる方法
3週間前
By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.説明されたエネルギー結晶と彼らが何をするか(黄色のクリスタル)
1週間前
By 尊渡假赌尊渡假赌尊渡假赌
スプリットフィクションを打ち負かすのにどれくらい時間がかかりますか?
3週間前
By DDD
ハローキティアイランドアドベンチャー:巨大な種を手に入れる方法
3週間前
By 尊渡假赌尊渡假赌尊渡假赌

人気の記事
レポ:チームメイトを復活させる方法
3週間前
By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.説明されたエネルギー結晶と彼らが何をするか(黄色のクリスタル)
1週間前
By 尊渡假赌尊渡假赌尊渡假赌
スプリットフィクションを打ち負かすのにどれくらい時間がかかりますか?
3週間前
By DDD
ハローキティアイランドアドベンチャー:巨大な種を手に入れる方法
3週間前
By 尊渡假赌尊渡假赌尊渡假赌

ホットな記事タグ

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

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

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

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

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

ホットトピック
Gmailメールのログイン入り口はどこですか?
7296
9


Java チュートリアル
1622
14


CakePHP チュートリアル
1342
46


Laravel チュートリアル
1259
25


PHP チュートリアル
1206
29



PHP と HTML の組み合わせ: コードを埋め込むための 3 つのテクニック

CENTOS7でmbstring拡張機能をインストールするにはどうすればよいですか?

最初から最後まで: PHP 拡張機能 cURL を使用して HTTP リクエストを行う方法

Aurora Push 拡張機能を使用して PHP アプリケーションにバッチ メッセージ プッシュ機能を実装する方法

PHP の ZipArchive 拡張機能を使用するにはどうすればよいですか?
