私は最近、仕事で非常に奇妙な問題に遭遇しました。 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值,而不是遍历数组本身。

PHPは、特にWeb開発の分野で、最新のプログラミングで強力で広く使用されているツールのままです。 1)PHPは使いやすく、データベースとシームレスに統合されており、多くの開発者にとって最初の選択肢です。 2)動的コンテンツ生成とオブジェクト指向プログラミングをサポートし、Webサイトを迅速に作成および保守するのに適しています。 3)PHPのパフォーマンスは、データベースクエリをキャッシュおよび最適化することで改善でき、その広範なコミュニティと豊富なエコシステムにより、今日のテクノロジースタックでは依然として重要になります。

PHPでは、弱い参照クラスを通じて弱い参照が実装され、ガベージコレクターがオブジェクトの回収を妨げません。弱い参照は、キャッシュシステムやイベントリスナーなどのシナリオに適しています。オブジェクトの生存を保証することはできず、ごみ収集が遅れる可能性があることに注意する必要があります。

\ _ \ _ Invokeメソッドを使用すると、オブジェクトを関数のように呼び出すことができます。 1。オブジェクトを呼び出すことができるように\ _ \ _呼び出しメソッドを定義します。 2。$ obj(...)構文を使用すると、PHPは\ _ \ _ Invokeメソッドを実行します。 3。ロギングや計算機、コードの柔軟性の向上、読みやすさなどのシナリオに適しています。

繊維はPhp8.1で導入され、同時処理機能が改善されました。 1)繊維は、コルーチンと同様の軽量の並行性モデルです。 2)開発者がタスクの実行フローを手動で制御できるようにし、I/O集約型タスクの処理に適しています。 3)繊維を使用すると、より効率的で応答性の高いコードを書き込むことができます。

PHPコミュニティは、開発者の成長を支援するための豊富なリソースとサポートを提供します。 1)リソースには、公式のドキュメント、チュートリアル、ブログ、LaravelやSymfonyなどのオープンソースプロジェクトが含まれます。 2)StackOverFlow、Reddit、およびSlackチャネルを通じてサポートを取得できます。 3)開発動向は、RFCに従うことで学ぶことができます。 4)コミュニティへの統合は、積極的な参加、コード共有への貢献、および学習共有への貢献を通じて達成できます。

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

PHPは死にかけていませんが、常に適応して進化しています。 1)PHPは、1994年以来、新しいテクノロジーの傾向に適応するために複数のバージョンの反復を受けています。 2)現在、電子商取引、コンテンツ管理システム、その他の分野で広く使用されています。 3)PHP8は、パフォーマンスと近代化を改善するために、JITコンパイラおよびその他の機能を導入します。 4)Opcacheを使用してPSR-12標準に従って、パフォーマンスとコードの品質を最適化します。

PHPの将来は、新しいテクノロジーの傾向に適応し、革新的な機能を導入することで達成されます。1)クラウドコンピューティング、コンテナ化、マイクロサービスアーキテクチャに適応し、DockerとKubernetesをサポートします。 2)パフォーマンスとデータ処理の効率を改善するために、JITコンパイラと列挙タイプを導入します。 3)パフォーマンスを継続的に最適化し、ベストプラクティスを促進します。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

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

WebStorm Mac版
便利なJavaScript開発ツール

MantisBT
Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

SublimeText3 Linux 新バージョン
SublimeText3 Linux 最新バージョン

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