よく質問されますが、foreach を使用して PHP 配列にアクセスする場合、トラバーサルの順序は決まっていますか?
例:
コードをコピーします コードは次のとおりです:
php
$arr['laruence'] = 'huixinchen';
$arr['baidu'] = 2008; ($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) 最小限の時間計算で配列の追加と削除を実装し、線形トラバーサルとランダム アクセスを同時にサポートします
これまでの記事でも説明しましたが、これに基づいてさらに拡張を行います。
HashTable について理解する前に、まず HashTable の構造定義を見てみましょう:
コードをコピー
コードは次のとおりです:
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;
unsigned char nApplyCount; /* ループトラバーサル保護* /
zend_debug
#endif
} HashTable; applyCount、理解できます例を通して:
コードをコピー
コードは次のとおりです:
$arr = array(1,2,3,4,5,);
$arr[] = & $arr;
var_export($arr); //致命的なエラー: ネストレベルが深すぎます - 再帰的な依存関係ですか?
上記の構造を見ると、このフィールドは循環参照によって引き起こされる無限ループを防ぐために設定されています。 HashTable の場合、キー要素は実際のストレージ コンテナである arBuckets であることがわかります。その構造定義を見てみましょう:
コードをコピー
コードは次のとおりです:
typedef struct Bucket。 {
ulong h; /* 数値インデックス/ハッシュ値*/
uint nKeyLength; /* 文字インデックスの長さ* /
void *pData; /* データポインタ*/
構造体*pListNext; /* 次の要素、線形走査用*/
struct Bucket *pListLast; /* 前の要素、線形走査に使用*/
struct Bucket *pNext; /* 同じジッパー内の次の要素*/
struct Bucket *pLast; /* 同じジッパー内の前の要素*/
char arKey[1 ]; /* メモリを節約し、初期化を容易にするためのヒント*/
最後の要素は、メモリを節約し、初期化を容易にする柔軟な配列手法であることに気付きました。興味のある方は、柔軟な配列を検索してください。
h は要素のハッシュ値であり、数値的にインデックス付けされた要素の場合は、h です。直接のインデックス値 (nKeyLength=0 で表される数値インデックス) 文字列インデックスの場合、インデックス値は arKey に格納され、インデックスの長さは nKeyLength に格納されます。 pData ポインタが指すメモリ ブロック。通常、このメモリ ブロックはシステムによって個別に割り当てられます。ただし、例外があります。つまり、バケットによって保存されたデータがポインターの場合、HashTable はシステムにポインターを保存するためのスペースの割り当てを要求せず、ポインターを pDataPtr に直接保存し、pData をメンバーにポイントします。この構造体のアドレス。これにより効率が向上し、メモリの断片化が軽減されます。このことから、PHP HashTable の設計の微妙な点がわかります。 Bucket 内のデータがポインターではない場合、pDataPtr は NULL になります (この段落は Altair の「Zend HashTable 詳細説明」から引用しています)
上記の HashTable 構造と組み合わせて、HashTable の一般的な構造図を図解してみましょう:
HashTable は線形リスト形式を指します。上の図では、最初の要素は要素 1 であり、pListTail は最後の要素 0 を指します。各要素について、pListNext は赤い線で描かれた線形構造の次の要素であり、pListLast は前の要素
pInternalPointer は、配列を順次に走査する場合、このポインターは現在の要素を示します。 Bucket.pListNext/pListLast は、pInternalPointer の移動に基づいてすべての要素の線形トラバーサルを実装します
たとえば、foreach の場合、生成されるオペコード シーケンスを見ると、foreach の前に最初に FE_RESET が存在することがわかります。配列 pInternalPointer である内部ポインター (foreach については、PHP の原理を詳しく理解するために foreach を参照してください) であり、各 FE_FETCH を通じて pInternalPointer をインクリメントして、順次走査を実現します
同様に、 each/next を使用する場合。走査する一連の関数 この場合、配列の内部ポインタを移動することによっても順次走査が可能になります。たとえば、次のような問題があります。
コードをコピー
コードは次のとおりです。 php $arr = array(1,2 ,3,4,5); foreach ($arr as $v) { //
を取得できます}
while (list($key, $v) = each( $arr)) {
//can't get To
}
?>
今紹介した知識を理解すれば、foreach は自動的にリセットされますが、while ブロックはリセットされないため、この問題は非常に明確になります。したがって、foreach が終了すると、pInternalPointer は配列を指します。もちろん、最後には while ステートメントのブロックにアクセスできなくなります。解決策は、それぞれの前に配列の内部ポインターをリセットすることです。
そして、ランダム アクセス中に、位置がリセットされます。ハッシュ配列の先頭ポインターの位置はハッシュ値によって決まります。次に、pNext/pLast を使用して特徴的な要素を見つけます。
要素を追加する場合、要素は同じハッシュ要素チェーンの先頭と末尾に挿入されます。つまり、線形リストの要素は、線形トラバース中に挿入順序に従って挿入されます。この特別な設計により、PHP では、数値インデックスを使用する場合、要素の順序は追加の順序によって決まります。
言い換えると、PHP で配列を走査する順序は、要素を追加する順序に関連しているため、記事の冒頭の質問の出力が次のようになることは明らかです。
コードをコピーします
コードは次のとおりです:
huixinchen
2007
2008 したがって、数値インデックス付き配列のインデックスサイズに従って反復処理を行いたい場合は、foreach の代わりに for を使用する必要があります
コードをコピーします
コードは次のとおりです:
for($i=0,$l=count( $arr); $i<$l; $i++) {
//このとき、逐次トラバーサル (線形トラバーサル) として考慮することはできません
} 原文: http://www.laruence.com/2009/08/ 23/1065.html
http://www.bkjia.com/PHPjc/325561.html
www.bkjia.com
true
http://www.bkjia.com/PHPjc/325561.html
技術記事 foreach を使用して PHP 配列にアクセスする場合、走査の順序は固定されていますか? 例: 次のようにコードをコピーします: ?php $arr['laruence'] =..
声明:この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。