PHP foreach循环使用一个条目两次

PHP foreach循环使用一个条目两次,php,mysql,arrays,pdo,foreach,Php,Mysql,Arrays,Pdo,Foreach,我只是在用PHP和PDO对MySQL数据库进行一点实验,我有点困惑,为什么在得到结果后,将它们正确地存储在多维数组中,并通过它们循环,它会两次输出一个数组数据 基本上,以下是获取数据的查询: SELECT b.Price, b.ImgURL, m.Name, f.ID, f.Family, f.URL FROM Products AS b INNER JOIN Manufacturers AS m ON m.ID = b.Manufacturer INNER JOIN FamilyLookUp

我只是在用PHP和PDO对MySQL数据库进行一点实验,我有点困惑,为什么在得到结果后,将它们正确地存储在多维数组中,并通过它们循环,它会两次输出一个数组数据

基本上,以下是获取数据的查询:

SELECT b.Price, b.ImgURL, m.Name, f.ID, f.Family, f.URL FROM Products AS b INNER JOIN Manufacturers AS m ON m.ID = b.Manufacturer INNER JOIN FamilyLookUp AS l ON l.Product = b.ID INNER JOIN Families AS f ON f.ID = l.Family GROUP BY f.ID ORDER BY b.Price ASC
我希望通过这个函数可以为每个族返回1行,这在PHPMyAdmin查询和打印结果时都能正常工作

然后我存储在:

$families[] = array('ID' => $f['ID'], 'Manufacturer' => $f['Name'], 'Family' => $f['Family'], 'URL' => $f['URL'], 'IMG' => $f['ImgURL'], 'Price' => $f['Price'], 'ScentCount' => 0);
在执行print_r()时,以及在foreach循环中回显每个条目的ID时,它也可以正常工作,返回1234567(所有7个族ID)

然后我运行另一个查询:

try{
$sqlCmd = "SELECT COUNT(*) FROM FamilyLookUp WHERE Family=:fID";
$s = $pdo->prepare($sqlCmd);
foreach($families as &$fam){
$s->bindValue(':fID', $fam['ID']);
$s->execute();
$fam['ScentCount'] = $s->fetchColumn();
}
}
这还可以获得正确的计数,并将其正确存储在每个族中项目数的数组中。到目前为止一切都很好

当我:

foreach($families as $fam):
        ?>

        <div class="product-listing">
        <?php echo $fam['ID']; ?>
            <div class="product-listing-image">
                <a href="<?php echo $fam['URL']; ?>"><img alt="" src="<?php echo $fam['IMG']; ?>"></a>
            </div>
            <div class="product-listing-details">

                <a href="<?php echo $fam['URL']; ?>"><h3><?php echo strtoupper($fam['Manufacturer']); if($fam['Family'] != ""){ echo strtoupper(' - ' . $fam['Family']);} ?></h3></a>
                <?php if($fam['ScentCount'] == 1): ?>
                <span class="product-scent-count"><?php echo $fam['ScentCount']; ?> Scent</span>
                <span class="product-price-value">£<?php echo $fam['Price']/100; ?></span>
                <?php elseif($fam['ScentCount']>1): ?>
                <span class="product-scent-count"><?php echo $fam['ScentCount']; ?> Scents</span>
                <span class="product-price-value">From £<?php echo $fam['Price']/100; ?></span>
                <?php endif;?>
            </div>
        </div>

        <?php
            endforeach;
        ?>

不管它有什么价值,第二双眼睛看不到代码的HTML输出部分有什么问题。这并没有改变你正在迭代的数组的结构,所以在我看来,也许你的诊断是不对的?值得对最后一个foreach循环进行注释,并将其替换为:

<?php foreach($families as $fam): ?>
    <?php var_dump($fam);?> 
<?php endforeach; ?>

这就是正在发生的事情:

在该循环的最后一次迭代中:

foreach($families as &$fam){
    $s->bindValue(':fID', $fam['ID']);
    $s->execute();
    $fam['ScentCount'] = $s->fetchColumn();
}
$fam指的是$families数组的最后一个元素

然后,当下一个循环开始时:

foreach($families as $fam){
。。。$fam指向的内存位置不变,但仍锁定到$families数组的最后一个元素。因此在第一次迭代中,第一个元素的内容被复制到$fam中,即在最后一个条目中,然后在第二次迭代中,第二个值被覆盖,依此类推。当最后一次迭代开始时,最后一个元素包含最后一个值,该值被。。。它本身也是最后一个值

这引发了同样的问题,给出的答案是这是故意的行为。作为对这一问题的回答,这一点说得很中肯:

目前的实施是一致的。当然,不是很有用, 但是在这里随意打断引用是不一致的。
PHP没有块作用域,破坏引用将引入 这里是特例块范围

这就用很好的插图解释了同样的行为

解决方案是在第二个循环中使用另一个新变量,如下所示:

foreach($families as $fam2){
unset($fam);
foreach($families as $fam){
或者,对于可能使用$fam的任何其他代码来说,更安全的方法是在第二个循环之前
unset($fam)
,如下所示:

foreach($families as $fam2){
unset($fam);
foreach($families as $fam){
这是因为在
foreach
循环开始时,变量从头开始重新创建,从而指向它自己的新内存位置

有一个关于此行为的警告,建议
取消设置

警告

$value
的引用和最后一个数组元素即使在
foreach
循环之后仍然保留。建议通过以下方式将其销毁

所有这些都很尴尬,当你阅读相关“bug”报告的回复时,很明显,你不是唯一一个遇到这种意外副作用的人。因此,我想强调这一点:

避免使用危险的
&
几乎不需要使用这个
&
前缀。通过避免它,这些奇怪的副作用将属于过去

您的代码可以在不使用
的情况下重写,如下所示:

foreach($families as $i => $fam){
    $s->bindValue(':fID', $fam);
    $s->execute();
    // use the index to put the value in place in the array:
    $families[$i]['ScentCount'] = $s->fetchColumn();
}

请注意,它也不会损害代码的可读性。

猜测:添加
unset($fam)在foreach循环之后:
foreach($families as&$fam){…
。您也可以停止使用
bindParam
。改用'bindValue'或只在'execute'语句中传递值?imo,您很少需要在PDO中使用'bindParam'。imo,您也不经常需要'bindParam'。imo,只需在
execute
中传递数据数组即可。也许可以交互?谢谢您的评论Ryan、 我已经在使用bindValue了。虽然我对学习PHP还比较陌生,但我肯定会更多地关注在execute方法中传递数据数组。当我添加unset($fam)时,这有点有趣在foreach循环结束时,kohloth建议它更改输出。从按1723466=ID为6的重复族的顺序输出数组,到1723461=ID为1的重复族噢,我的天哪。非常感谢你的帮助。当放置在foreach循环结束之后时,未设置的东西实际上起作用了,我以为你是指内部可执行代码结束后的循环。我一定会尝试仅在函数中需要时使用foreach循环。无论如何,我不能想象有太多的引用在运行是多么好。非常感谢,经常使用foreach循环!除非你真的必须使用,否则不要在PHP中使用“&$var”。而且你不应该这样做。很高兴你得到了它被整理好了-感谢收听:)请查看@trincot提供的答案,以了解正在发生的事情。:)感谢您的回答。这看起来真的很奇怪。我已经按照建议在for循环中添加了vardump,它给出了相同的结果(重复最后一个数组)。即使它直接在打印后显示正确的数据。为了让它稍微短一点,我删除了一堆行,但将ID作为一个编辑器。当您在视图代码的正上方显式声明一个结构类似的数组时会发生什么?当我使用显式声明的数组时,它似乎工作正常。有什么想法吗当使用存储在我列出的数组中的数据库数据时,可能是什么导致了它的混乱?谢谢你对发生的事情给出了更清晰的解释。谢谢你的详细解释。我只是假设$fam只存在于循环中。非常酷,一定会阅读链接的材料,然后是一些!非常感谢