PHP 配列のポインターに関するちょっとした考え_PHP チュートリアル

WBOY
リリース: 2016-07-13 10:32:52
オリジナル
919 人が閲覧しました

私は最近、仕事で非常に奇妙な問題に遭遇しました。 each 関数を使用して配列を走査した後、配列は実際のパラメータとして関数に渡され、それぞれが関数内で仮パラメータ グループを走査するために再度使用されます。説明すると、 each 関数を 2 回使用する目的は非常に単純で、配列内のキーを変数名に変換し、キーに対応する値を変数の値に変換することです。実際、この機能は、extract 関数を使用して実現できます。次に、関数内で各関数を使用するときに発生した問題について説明します。走査した結果、一部の変数が NULL であることがわかりました。これは、一部の変数が失われていることを意味します。説明が明確かどうかはわかりませんが、問題を単純化し、次のコードで説明してみましょう。

リーリー

出力結果: NULL NULL NULL NULL NULL int(6).

従来の考え方によれば、この時点で変数 $var1、$var2、$var3、$var4、$var5、$var6 はすべて関数 func 内に存在するはずですが、変数 $var6 だけがそうではありません。値があり、その他のいくつかの変数は NULL です。どうしてこれなの?

問題は、今日議論する配列ポインタの問題にあります。各関数は、現在の配列ポインターが指す要素を配列の形式で返し、配列ポインターを 1 ビット進めて次の配列ユニットを指します。 each 関数を使用して配列 $arr を走査すると、$arr 配列の内部ポインタはすでに最後のユニットの次のビット (値なし) を指しています。この時点で、$arr['var6'] = 6 という操作を実行し、配列に新しいユニットを追加しました。配列はメモリ内の連続したアドレス単位に格納する必要があることがわかっています。つまり、メモリ内の $arr['var6'] の値の位置は、現在の配列ポインタが指すユニット内にある必要があります (以前は空でした)。さらに、配列に値を代入しても、配列の内部ポインタは移動しません。代入が完了すると、$arr 配列の配列ポインタは、NULL を指す状態から、実際の値を持つアドレス ユニットを指すように変わります。

配列が関数間でパラメーターとして渡される場合には、別のルールがあります。関数が呼び出されるとき、システムは実際のパラメーターをコピーし、それらを仮パラメーター (参照呼び出しを除く) に割り当てることがわかっていますが、配列の場合はそれだけではありません。実際のパラメータはパラメータの値がコピーされ、実際のパラメータ グループの現在の内部ポインタの位置もコピーされます。実パラメータの内部ポインタの位置が配列の末尾を指している場合、システムは、仮パラメータ グループの最初のユニットを指すように仮パラメータの内部ポインタをリセットします。実パラメータが配列の末尾になく、有効なユニットを指している場合、システムは仮パラメータの配列ポインタ位置を、実パラメータの配列ポインタと同じ値を持つ配列ユニットを指します。

$arr['var6'] = 6 を実行しない場合、6 つの変数すべて ($var1-$var6) に値が含まれます。これは、各変数の後で、配列ポインタが配列の末尾を指しているためです。関数 func() を使用すると、システムは $arrtmp の配列ポインタを最初の要素を指すようにリセットします。しかし、操作 $arr['var6'] = 6 の後では、すべてが変わりました。この操作により、$arr の配列ポインターが NULL を指していたのから有効な値に変わりました (代入の前後で、配列のアドレス単位が指していたことを説明してください)。ポインタによる値は変化していません。代入前はそのアドレス単位に何もなかったのですが、代入後は 6) になりました。これにより、$arr の配列ポインタが有効なユニットを指すようになります。関数 func() を呼び出すとき、システムは $arrtmp の配列ポインタをリセットしません。$arr の配列ポインタは同じになります。同様に、彼自身の最後のユニットを指します。 each 関数は、現在の配列ポインターの位置から動作を開始します。したがって、各関数の演算の最初の結果の戻り値は配列 $arrtmp の最後の要素であり、これにより配列ポインタが 1 ビット下に移動します。したがって、$arrtmp['var1']-$arrtmp となります。 ['var5'] は走査されていないため、最終的に $var1 ~ $var6 が NULL になります。

配列の代入の過程で、代入する配列と代入される配列の配列ポインタが変化します。 最初に結論を与え、次にコードを使用してこの結論を証明します。 $arrtmp=$arr; この代入式では、$arr を代入配列、$arrtmp を代入配列と呼びます。配列が割り当てられるとき、割り当てられた配列の配列ポインタがすでに配列の末尾を指している場合、割り当てられた配列の配列ポインタは割り当て後にリセットされ、割り当て中の場合は配列の最初の要素を指します。 、割り当てられた配列の配列ポインタは、最後に有効な配列要素を指していません。その場合、割り当てられた配列の配列ポインタは、割り当て後にリセットされず、元の配列要素が指していました。保持されます。代入後、割り当てられた配列には割り当てられた配列の値が含まれるだけでなく、割り当てられた配列の配列ポインタもその要素を指し、割り当てられた配列自体も同じ値を持つ要素を指すようになります。

デモ1:

<?php
	$arr = array('var1'=>1,'var2'=>2,'var3'=>3,'var4'=>4,'var5'=>5);
	while( list($key,$value) = each($arr) )
	{
		if($value == 4) break;
	}
	var_dump(current($arr));
	
	$arr1 = $arr;
	
	var_dump(current($arr));
	var_dump(current($arr1));
?>
ログイン後にコピー

demo1 的执行结果是:int(5) int(5) int(5) 。从这个结果可以看出,赋值前后$arr的数组指针位置没有发生任何变化,$arr1不仅值跟$arr相同,而且数组指针所指向的元素值也是相同的。现在 用上述结论来解释这个结果,在while循环中,有一个if判断语句,目的是不让$arr的数组指针指向数组末尾,而是保留在一个有效的位置。 在$value=4时会跳出循环,而each这个函数会将数组指针向前移动一位,这就导致了$arr的数组指针指向了第5个元素,所以在赋值之 前,current($arr)的结果是5,赋值之后,由于在赋值之前$arr的当前指针并没有指向末尾,因此在赋值之后不会将$arr的数组指针进行重 置,而是保留了其原有的位置,因此在赋值之后使用current($arr)的结果仍然是5。赋值时$arr1不仅获得了$arr的值,而且数组指针指向 的元素和$arr的相同,二者都是5。

demo2:

<?php
$arr = array('var1'=>1,'var2'=>2,'var3'=>3,'var4'=>4,'var5'=>5);
while( list($key,$value) = each($arr) )
{
    //if($value == 4) break;
}
var_dump(current($arr));
$arr1 = $arr;
var_dump(current($arr));
var_dump(current($arr1));
?>
ログイン後にコピー

demo2中我们将 if($value == 4) break; 这一句注释掉了,目的很简单,就是通过each将$arr的数组指针位置指向数组末尾。

demo2 的执行结果:bool(false) int(1) bool(false) 。如果数组指针对应的元素为0,"",或者不是一个有效的值时,current函数会返回false,$arr的值中没有为0或者""的情况,因此可以断 定是因为数组指针指向了一个无效的元素而导致current返回了一个false。换句话说就是可以确定在while循环完成之后,$arr的数组指针已 经指向了数组的末尾。所以我们看到在赋值之前current($arr)的值是false,而赋值之后current($arr)的值变成了1,说明赋值 之后$arr的数组指针被重置了,指向了数组的第一个元素。current($arr1)的值为false,说明赋值之后$arr1让然保留了赋值之 前$arr的数组指针指向的元素。

通过demo1和demo2就可以证明上述结论了。

因此为了在遍历数组时不受数组指针的影响,最好在使用each()函数之前或者之后调用函数reset()将数组指针重置。这样就可以避免上述问题的发生了。另外还有一个操作数组指针的函数prev(),它的作用是将数组指针当前的位置后退一位,它也需要注意一点,就是如果数组指针已经指向数组末尾,那么使它就得不到想要的结果了。

顺便说一下foreach这个函数,使用foreach函数来遍历数组时,它会重置数组指针,将其指向数组的第一个元素。必须注意的是foreach操作的对象是对你要遍历的数组的copy值,而不是遍历数组本身。

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/752585.htmlTechArticle最近在工作中遇到一个很奇怪的问题,在使用each这个函数对一个数组遍历之后,再把该数组作为实参传递给一个函数,在函数内部再次使用...
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート