ホームページ > php教程 > php手册 > PHP 配列の深い理解 (走査順序) Laruence オリジナル

PHP 配列の深い理解 (走査順序) Laruence オリジナル

WBOY
リリース: 2016-06-13 11:59:55
オリジナル
838 人が閲覧しました

よく質問されますが、foreach を使用して PHP 配列にアクセスする場合、走査の順序は固定されていますか?
例:

コードをコピーします。 🎜> コードは次のとおりです。

$arr['laruence'] = 'huixinchen'
$arr['yahoo'] = 2007;
$arr['baidu'] = 2008;
foreach ($arr as $key => $val) {
//結果は何ですか? 🎜>
別の例:


コードをコピー

コードは次のとおりです: $arr[2] = 'huixinchen';

$arr[1] = 2007;

$arr[0] = 2008;
foreach ($arr as $key => $val) 🎜>//結果はまた何ですか?
}


この問題を完全に理解するには、まず PHP 配列の内部実装構造を理解する必要があると思います...

PHP 配列
PHP では、配列は HASH 構造 (HashTable) を使用して実装され、O(1) 時間の計算量で配列の追加と削除を可能にし、線形トラバーサルとランダムの両方をサポートします。


これまでの記事でも PHP の HASH アルゴリズムについて説明しましたが、これに基づいて

HashTable を理解する前に、まず見てみましょう。 HashTable の構造定義 I 誰でも理解できるようにコメントを追加します:



コードをコピー

コードは次のとおりです:

typedef struct _hashtable { uint nTableSize; / * ハッシュ テーブルのサイズ、ハッシュ値の範囲*/ uint nTableMask; /* nTableSize -1 に等しい、*/

uint nNumOfElements; HashTable 内の実際の要素数*/

ulong nNextFreeElement; /* 次に使用可能な空き位置の数値インデックス*/
Bucket *pInternalPointer; /* リセットされる現在の位置ポインター。関数は */
Bucket *pListHead; /* 線形トラバーサルに使用されるヘッド要素 */
Bucket *pListTail; /* 線形トラバーサルに使用される */
Bucket **arBuckets;実際のストレージコンテナ*/
dtor_func_t pDestructor;/* 要素デストラクター (ポインター) */
zend_boolpersistent; /* ループトラバーサル保護*/
zend_bool bApplyProtection; if ZEND_DEBUG
int inconsistent;
#endif
} HashTable;


nApplyCount の意味については、次の例で理解できます。 >
コードをコピー

コードは次のとおりです:

$arr = array(1,2,3,4,5,) ;
$arr[] = &$arr;

var_export($arr); //致命的なエラー: ネスト レベルが深すぎます - このフィールドは

上記の構造を見ると、HashTable のキー要素は実際のストレージ コンテナーである arBuckets であることがわかります。構造体定義:



コードをコピーします

コードは次のとおりです。



typedef structbucket {
ulong h; * 数値インデックス/ハッシュ値*/
uint nKeyLength; /* 文字インデックス長*/

void *pData; /* data*/ void *pDataPtr; /* データ ポインタ */ struct Bucket *pListNext; /* 次の要素、線形走査用*/ struct Bucket *pListLast; /* 前の要素、線形走査に使用*/ struct Bucket *pNext; /* 同じジッパー内の次の要素/

struct Bucket *pLast; /* 同じジッパー内の前の要素*/

char arKey[1] /* メモリを節約し、初期化を容易にするためのヒント*/
} Bucket;


最後の要素は、メモリを節約し、初期化を容易にする柔軟な配列手法であることに気付きました。興味のある方は、柔軟な配列を検索してください。
h は、数値インデックス付きの要素のハッシュ値です。要素、h は直接のインデックス値 (nKeyLength=0 で表される数値インデックス) です。文字列インデックスの場合、インデックス値は arKey に格納され、インデックスの長さはバケット内の
に格納されます。データは、pData ポインタが指すメモリ ブロックに格納されます。通常、このメモリ ブロックはシステムによって個別に割り当てられます。ただし、例外があります。つまり、バケットによって保存されたデータがポインターの場合、HashTable はシステムにポインターを保存するためのスペースの割り当てを要求せず、ポインターを pDataPtr に直接保存し、pData をメンバーにポイントします。この構造の。これにより効率が向上し、メモリの断片化が軽減されます。このことから、PHP HashTable の設計の微妙な点がわかります。 Bucket 内のデータがポインタでない場合、pDataPtr は NULL になります (この段落は Altair の「Zend HashTable 詳細説明」から引用しています)
上記の HashTable 構造と組み合わせて、HashTable の全体的な構造図を示します。

HashTable pListthHead は線形リスト形式の最初の要素 (上の図では要素 1) を指し、pListTail は最後の要素 0 を指し、各要素の pListNext は赤い線で描かれた線形構造の次の要素です

pInternalPointer は、配列を順次走査する場合、現在の要素を示します。

このとき、pListHead から開始し、Bucket 内の pListNext/pListLast をたどり、pInternalPointer の動きに従って pInternalPointer を移動して、すべての要素の線形走査を実現します。

たとえば、foreach の場合。生成されるオペコード シーケンスを見てください。foreach の前に、まず配列の内部ポインタである pInternalPointer をリセットする FE_RESET があることがわかります (foreach については、PHP 原理の詳細な理解である Foreach を参照してください)。

同様に、各 FE_FETCH で pInternalPointer をインクリメントし、逐次探索を実行します。

同様に、関数の each/next を使用して、配列の内部ポインタを移動することで逐次探索も実現します。 コードをコピー

コードは次のとおりです:


$arr = array(1,2,3,4,5);
foreach ($arr as $v) {
//
}

while (list($ key, $v) = each($arr)) {
/ /Cannot get
}

?>


今紹介した知識を理解すると、この問題はforeach は自動的にリセットされますが、while はリセットされないため、非常に明確にしてください。そのため、foreach が終了すると、pInternalPointer は配列の末尾を指します。もちろん、while ステートメント ブロックは内部配列にアクセスできません。

そしてランダムアクセスの場合、ハッシュ配列の先頭ポインタの位置がハッシュ値によって決定され、pNext/pLast によって特徴的な要素が見つかります。 >
要素を追加する場合、要素は同じハッシュ要素チェーンの先頭と末尾に挿入されます。つまり、要素は線形走査中の挿入順序に従って走査されます。この特別な設計により、PHP で数値インデックスを使用する場合、要素の順序はインデックスの順序ではなく、加算の順序によって決まります。つまり、PHP で配列が走査される順序が決まります。要素が追加される順序です。これで、記事の冒頭の質問の出力が次のとおりであることが明確になりました。

コードをコピー コード

huixinchen
2007
2008

したがって、数値インデックス付き配列のインデックス サイズによって反復処理を行いたい場合は、次のようにする必要があります。 foreach の代わりに for を使用します

コードをコピー コードは次のとおりです:

for($i=0,$l= count($arr); $i<$l; $i ) {
//現時点では、逐次走査 (linear Traverse) とはみなされません
}

テキスト: http://www.laruence.com/2009/08/23/1065.html

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のおすすめ
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート