PHP-发现这个foreach中的问题了吗


PHP - Spot the problem in this foreach?

我正在创建一个简单的订单车。

从本质上讲,用户单击订单,产品id将作为数组添加到会话变量($order(中。查看"cart"时,会进行检查,如果会话变量中的值等于mysql表中特定行的id,则该特定行将作为已排序的项返回。对于会话变量中的每个值,此过程都应该重复出现。

以下是我正在与之斗争的代码:

foreach ($order as $item) 
{
    while($row = mysql_fetch_assoc($productsSql))
    {
         $itId = $row['id'];
         $itDesc = $row['desc'];
         $itPrice1 = $row['price1'];
         if ($item == $itId) 
        {
        $pageContent .= '
                <tr>
                    <td>'.$itDesc.'</td>
                    <td>
                        R'.number_format($itPrice1, 2).'
                    </td>
                </tr>
';      
        }
    }   
}

"$orders"变量如下:

session_start();
if (!isset($_SESSION['order']))
{
$_SESSION['order'] = array();
}

有人能发现这个问题吗?

$productsQuery = 'SELECT `id`, `refCode`, `desc`, `pack`, `measure`, `quantity`, `deptCode`, `taxable`, `price1`, `price2`, `crdCode`, `cost1`, `cost2` FROM `products` ORDER BY `desc` ';
$productsSql = mysql_query($productsQuery) or die(mysql_error());`
while($row = mysql_fetch_assoc($productsSql))

这不会在每个$item中重现,所以在foreach之前将行保存在数组中,并将此while替换为foreach

尝试这个

mysql_data_seek($productsSql,0(;

foreach ($order as $item) 
{
mysql_data_seek( $productsSql, 0);  //<- this line, to reset the pointer for every EACH.
    while($row = mysql_fetch_assoc($productsSql))
    {
         $itId = $row['id'];
         $itDesc = $row['desc'];
         $itPrice1 = $row['price1'];
         if ($item == $itId) 
        {
        $pageContent .= '
                <tr>
                    <td>'.$itDesc.'</td>
                    <td>
                        R'.number_format($itPrice1, 2).'
                    </td>
                </tr>
';      
        }
    }   
}

希望对有所帮助

您还没有指定$productsSql的内容,但包含它的行看起来是错误的。

如果$productsSql包含SQL代码,那么它根本不起作用,因为mysql_fetch_assoc()需要数据库资源。要获得资源,您需要使用SQL代码调用mysql_query()

假设您在引用的代码之外调用了mysql_query(),并且$productsSql确实包含结果资源,那么这仍然是错误的,因为您多次循环数据库结果(因为foreach循环(,但没有重置或重新查询。

这样做的结果是,在foreach的第一次迭代之后,while循环将贯穿数据库查询中的所有结果,并将被设置到结果集的末尾。循环回到代码的顶部不会改变结果集的位置,所以当它第一次尝试在第二次循环中调用mysql_fetch_assoc()时,它会说"我已经完成了",什么都不会发生。

如果希望foreach循环的每次迭代都处理相同的结果集,则需要在启动while循环之前重置DB指针。这可以通过mysql_data_seek()函数来完成。

使用您提供的代码,这可能会达到您想要的效果。

然而,这可能不是达到你想要的结果的最有效的方法。不幸的是,如果没有看到更多的代码(特别是SQL查询和更多的数据结构(,很难更具体地说明如何改进它。

[EDIT]在OP将SQL查询添加到问题中后,我们可以更清楚地看到最佳操作方案是什么。

一个快速而肮脏的解决方案确实是使用mysql_data_seek(),正如我上面解释的那样(如@Phoenix的代码所示(,但尽管这会使程序正常工作,但效率会非常低,尤其是在向数据库添加更多产品时。

实际需要的是从SQL查询本身开始对代码进行彻底的更改。

需要将查询更改为仅包括实际需要的项。这将使用WHERE子句来完成,因此查询可能看起来像这样:

SELECT <lots of fields> FROM products WHERE id IN(5,7,9,<etc>)

这很容易生成,因为$orders看起来是一个项目ID的数组,所以您可以简单地使用implode(',',$orders)来制作一个适用于WHERE子句的ID列表。(不过,您需要绝对确定它们都是数字ID,因为其他任何东西都会破坏SQL查询;如果您不确定,则应该首先对它们进行SQL转义(。

一旦获得了该列表,最好的方法是将DB值加载到内存数组中,然后使用foreach($order)循环获取适当的数组元素。

所以你的最终代码看起来像这样:

$productsQuery = 'SELECT `id`, `refCode`, `desc`, `pack`, `measure`, `quantity`, `deptCode`, `taxable`, `price1`, `price2`, `crdCode`, `cost1`, `cost2` FROM `products` WHERE id IN('.implode(',',$orders).')';
$productsSql = mysql_query($productsQuery) or die(mysql_error());`
$data = array();
while($row = mysql_fetch_assoc($productsSql)) {
    $data[$row['id']] = $row;
}
foreach($order as $item) {
   $pageContent .= '
            <tr>
                <td>'.$row[$item]['desc'].'</td>
                <td>
                    R'.number_format($row[$item]['price'], 2).'
                </td>
            </tr>
    ';
}