Zendサイクルバイパスマクロ(HashTable Iteration)

PHP(7.0.7)のソースコードの表面的な調査を続け、 最も単純な拡張機能を記述します。今回は、単純なPHP中央値()関数を実装するときに出会った、受け入れられた関数引数を介して配列を走査する方法についてもう少し詳しく説明します。 この関数のタスクは単純です-算術平均値を返すこと。 おそらく、この出版物は、私のような他のPHP開発者にとっては役に立つでしょう。私は、自由時間に、お金を稼ぐお気に入りの言語のアーキテクチャを少し勉強することに決めました。 前の出版物で、階乗計算機能の実装を使用してPHPで拡張機能を迅速に作成する手法をまとめました。 整数型の単純なパラメーターを受け取り、再帰的に呼び出されるという点で単純です。 median()関数の実装は、受け入れられたパラメーターが配列であるという事実によって複雑になっています。合計値を合計し、配列内の要素の合計数を計算するためにそれを実行する必要があります。



現時点では、配列のすべての受け入れられた要素が数字であることを知っているという事実によって、タスクを単純化しました。 PHP拡張モジュールのソースコードは、ここでマクロを使用して「すべてが記述されている」という点で驚くべきものです。 少なくともそのような最初の意見が作成されます。 マクロは配列内の要素のリストを走査するためにも使用されることがわかります。 わかりやすくするために、機能コードの後に​​簡単な説明を続けます。



関数はすべて同じファイルに記述されています-mathstat.c拡張mathstat。 githubへのリンク



mathstat拡張機能のリスト:



const zend_function_entry mathstat_functions[] = { PHP_FE(confirm_mathstat_compiled, NULL) /* For testing, remove later. */ PHP_FE(ms_factorial, arginfo_ms_factorial) PHP_FE(ms_median, NULL) PHP_FE_END /* Must be the last line in mathstat_functions[] */ };
      
      







関数本体のまさに定義:



 PHP_FUNCTION(ms_median) { int argc = ZEND_NUM_ARGS(); double total = 0; int count = 0; zval *array, *value; if (zend_parse_parameters(argc, "a", &array) == FAILURE) { RETURN_DOUBLE(0); } ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), value) { total = total + zval_get_double (value); count += 1; } ZEND_HASH_FOREACH_END(); if (count == 0 || total == 0) { RETURN_DOUBLE(0); } RETURN_DOUBLE(total/count); }
      
      







関数の本体を見ると、前回と同様に、パラメーターチェック関数が呼び出されます。引数の受け入れられた型のテンプレートとして、値 "a"(配列)を設定します



  if (zend_parse_parameters(argc, "a", &array) == FAILURE) { RETURN_DOUBLE(number); }
      
      







ここで最も興味深い部分は、マクロZEND_HASH_FOREACH_VALを介して実装されるループスルーです。 合計で、参照で見つけた配列を通過するマクロは7個です。 同時に、配列の代わりにHashTableという用語がどこでも使用されます。 このケースでは、最も単純なマクロを選択しました。 最初の引数は関数を介して受信した配列を受け取り、2番目のzval(値とデータ型を格納する基本的なデータ構造-Dmitry Stogovのこの部分のビデオ )。 この場合、zval_get_double関数を呼び出すだけです。これは、大まかに言って、配列から値を返します。 これを通常のPHPコードに書き換えると、次のようになります。



  1 <?php 2 $array = [1,2,3]; 3 4 $number = 0; 5 $count = 0; 6 7 foreach($array as $val) { 8 $number += $val; 9 $count += 1; 10 } 11 12 echo "cnt: ".$count." total: ".$number."\n"; 13 ?>
      
      







つまり、実際には、マクロを使用するだけで複雑なものはなく、同じレコードです。 別のより高度なマクロを見ると、



 ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val)
      
      







コードがなければ、これがphpループの類似物であることはすでに明らかです。



 foreach($array as $key => $value) { }
      
      







明確にするために、ディレクトリからすべてのマクロを提供します。



 ZEND_HASH_FOREACH_VAL(ht, val) ZEND_HASH_FOREACH_KEY(ht, h, key) ZEND_HASH_FOREACH_PTR(ht, ptr) ZEND_HASH_FOREACH_NUM_KEY(ht, h) ZEND_HASH_FOREACH_STR_KEY(ht, key) ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) ZEND_HASH_FOREACH_KEY_VAL(ht, h, key, val)
      
      







以上です。 かかった時間とモバイルトラフィックの損失をありがとう。



All Articles