PHP指针和变量冲突

发布于 2024-12-11 20:15:49 字数 678 浏览 0 评论 0原文

我有一个关于 PHP 以及指针和变量的使用的问题。

以下代码产生了我意想不到的结果:

<?php
$numbers = array('zero', 'one', 'two', 'three');

foreach($numbers as &$number)
{
  $number = strtoupper($number);
}

print_r($numbers);

$texts = array();
foreach($numbers as $number)
{
  $texts[] = $number;
}

print_r($texts);
?>

输出如下

Array
(
    [0] => ZERO
    [1] => ONE
    [2] => TWO
    [3] => THREE
)
Array
(
    [0] => ZERO
    [1] => ONE
    [2] => TWO
    [3] => TWO
)

请注意“TWO”在第二个数组中出现了两次。

两个 foreach 循环之间似乎存在冲突,每个循环都声明一个 $number 变量(一次通过引用,第二次通过值)。

但为什么 ?为什么它只影响第二个 foreach 中的最后一个元素?

I have a question about PHP and the use of pointers and variables.

The following code produces something I wouldn't have expected:

<?php
$numbers = array('zero', 'one', 'two', 'three');

foreach($numbers as &$number)
{
  $number = strtoupper($number);
}

print_r($numbers);

$texts = array();
foreach($numbers as $number)
{
  $texts[] = $number;
}

print_r($texts);
?>

The output is the following

Array
(
    [0] => ZERO
    [1] => ONE
    [2] => TWO
    [3] => THREE
)
Array
(
    [0] => ZERO
    [1] => ONE
    [2] => TWO
    [3] => TWO
)

Notice the 'TWO' appearing twice in the second array.

It seems that there is a conflict between the two foreach loops, each declaring a $number variable (once by reference and the second by value).

But why ? And why does it affect only the last element in the second foreach ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

疑心病 2024-12-18 20:15:49

关键是PHP没有指针。它有references,这是一个相似但不同的概念,并且有一些微妙的地方差异。

如果您使用 var_dump() 而不是 print_r(),则更容易发现:

$collection = array(
    'First',
    'Second',
    'Third',
);

foreach($collection as &$item){
    echo $item . PHP_EOL;
}

var_dump($collection);

foreach($collection as $item){
    var_dump($collection);
    echo $item . PHP_EOL;
}

... prints:

First
Second
Third
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(5) "Third"
}
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(5) "First"
}
First
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(6) "Second"
}
Second
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(6) "Second"
}
Second

请注意最后一个数组项中留下的 & 符号。

总而言之,每当您在循环中使用引用时,最好在最后删除它们:

<?php

$collection = array(
    'First',
    'Second',
    'Third',
);

foreach($collection as &$item){
    echo $item . PHP_EOL;
}
unset($item);

var_dump($collection);

foreach($collection as $item){
    var_dump($collection);
    echo $item . PHP_EOL;
}
unset($item);

...每次都会打印预期的结果。

The key point is that PHP does not have pointers. It has references, which is a similar but different concept, and there are some subtle differences.

If you use var_dump() instead of print_r(), it's easier to spot:

$collection = array(
    'First',
    'Second',
    'Third',
);

foreach($collection as &$item){
    echo $item . PHP_EOL;
}

var_dump($collection);

foreach($collection as $item){
    var_dump($collection);
    echo $item . PHP_EOL;
}

... prints:

First
Second
Third
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(5) "Third"
}
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(5) "First"
}
First
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(6) "Second"
}
Second
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(6) "Second"
}
Second

Please note the & symbol that's left in the last array item.

To sum up, whenever you use references in a loop, it's good practice to remove them at the end:

<?php

$collection = array(
    'First',
    'Second',
    'Third',
);

foreach($collection as &$item){
    echo $item . PHP_EOL;
}
unset($item);

var_dump($collection);

foreach($collection as $item){
    var_dump($collection);
    echo $item . PHP_EOL;
}
unset($item);

... prints the expected result every time.

凑诗 2024-12-18 20:15:49

即使在循环之后变量 $number 也会被初始化,您需要通过 unset 来中断引用

此代码可以正常工作:

<?php
$numbers = array('zero', 'one', 'two', 'three');

foreach($numbers as &$number)
{
  $number = strtoupper($number);
}

print_r($numbers);
unset($number);

$texts = array();
foreach($numbers as $number)
{
  $texts[] = $number;
}

print_r($texts);
?>

http://www.php.net/manual/en/language.references.unset.php

当您取消设置引用时,您只是打破了变量名称和变量内容之间的绑定。这并不意味着可变内容将被破坏。

...将此视为类似于 Unix 取消链接调用。

http://uk.php.net/manual/en/control-结构.foreach.php

有关 foreach 的警告

即使在 foreach 循环之后,$value 和最后一个数组元素的引用仍然保留。建议通过unset()销毁。

variable $number is initialized even after loop , you need to break the reference by unset

this code works properly:

<?php
$numbers = array('zero', 'one', 'two', 'three');

foreach($numbers as &$number)
{
  $number = strtoupper($number);
}

print_r($numbers);
unset($number);

$texts = array();
foreach($numbers as $number)
{
  $texts[] = $number;
}

print_r($texts);
?>

http://www.php.net/manual/en/language.references.unset.php

When you unset the reference, you just break the binding between variable name and variable content. This does not mean that variable content will be destroyed.

...think about this as analogous to the Unix unlink call.

http://uk.php.net/manual/en/control-structures.foreach.php

Warning about foreach

Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset().

向日葵 2024-12-18 20:15:49

您应该在第一个循环后中断引用。

foreach($numbers as &$number)
{
   $number = strtoupper($number);
}    
unset($number);

文档中所述:

警告 $value 的引用和最后一个数组元素仍然存在
即使在 foreach 循环之后。建议通过以下方式销毁它
取消设置()。

另外,如果您使用 var_dump() 而不是 print_r(),您会注意到第一个循环后数组的最后一个元素是一个引用:

array(4) {
[0]=>
string(4) "ZERO"
[1]=>
string(3) "ONE"
[2]=>
string(3) "TWO"
[3]=>
&string(5) "THREE"
}

如果您遵循 Stefan Gehrig 对问题的评论,有一个链接可以完美地解释此行为:
http://schlueters.de/blog/archives/141-References- and-foreach.html

You should break the reference after the first loop.

foreach($numbers as &$number)
{
   $number = strtoupper($number);
}    
unset($number);

as stated in documentation:

Warning Reference of a $value and the last array element remain
even after the foreach loop. It is recommended to destroy it by
unset().

Also, if you use var_dump() instead of print_r(), you'll notice that the last element of array after the first loop is a reference:

array(4) {
[0]=>
string(4) "ZERO"
[1]=>
string(3) "ONE"
[2]=>
string(3) "TWO"
[3]=>
&string(5) "THREE"
}

If you follow Stefan Gehrig's comments on question, there is a link that perfectly explains this behaviour:
http://schlueters.de/blog/archives/141-References-and-foreach.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文