如何构造一个合适的 foreach()

Posted

技术标签:

【中文标题】如何构造一个合适的 foreach()【英文标题】:how construct a proper foreach() 【发布时间】:2019-08-07 12:55:36 【问题描述】:

刚开始的伙计们,我必须注意...我根本就是个菜鸟:)

我尝试在本地 Windows 机器(IIS、php 5.2、MSSQL)上运行脚本并出现错误:

PHP Notice:  Undefined variable: table in C:\Inetpub\wwwroot\XX.php on line 38
PHP Warning:  Invalid argument supplied for foreach() in C:\Inetpub\wwwroot\XX.php on line 12

脚本:

<?php
$user = 'xx';
$pass = 'xx';
$host = '10.0.2.15';
$dbname = 'Game3G';
try
$dbh = new PDO ("mssql:host=$host;dbname=$dbname", "$user", "$pass");
$n=0;  
function sorting($next,$table) 
$temp=0;

foreach($table as $entry) if($entry['position']==0) if($entry['level']>=$temp['level'] && $entry['exp']>=$temp['exp']) $temp=$entry;
if($temp) 
$table[$temp['id']]['position']=$next;
echo '<tr>
     <td  style="font-size: 10px;">'.$next.'</td><td  style="font-size: 10px;">'.$temp['character'].'</td><td style="font-size: 10px;">'.$temp['level'].'</td> <td   style="font-size: 10px; text-align: right;">'.$temp['exp'].'%</td>
     </tr>
   ';
sorting($next+1,$table);




echo '<br> <table   border=0  >';
$i=0;
foreach ($dbh->query('SELECT TBL_CHARACTER.FLD_LEVEL, TBL_CHARACTER.FLD_jOB, TBL_CHARACTER.FLD_CHARACTER, TBL_ABILITY.FLD_MAXEXP, TBL_ABILITY.FLD_EXP from TBL_CHARACTER LEFT JOIN TBL_ABILITY ON(TBL_CHARACTER.FLD_CHARACTER = TBL_ABILITY.FLD_CHARACTER) where TBL_CHARACTER.FLD_LEVEL < 69 and TBL_CHARACTER.FLD_jOB = 2 and TBL_CHARACTER.FLD_DELETED = 0 order by TBL_ABILITY.FLD_EXP + TBL_ABILITY.FLD_LEVEL * TBL_ABILITY.FLD_MAXEXP desc') as $row)

$i++;
$table[$i-1]['level']=$row['FLD_LEVEL'];
$table[$i-1]['character']=$row['FLD_CHARACTER'];
$table[$i-1]['exp']=round(($row['FLD_EXP']/$row['FLD_MAXEXP'])*100);
$table[$i-1]['id']=$i-1;
$table[$i-1]['position']=0;

$n++;
 if($n>=10) break;
;
sorting(1,$table);
echo '</table><br>';
$dbh = null;    
 
 catch(PDOException $e)
     echo 'Statystyki niedostępne.';
   
/*end*/            
?>

脚本应该生成包含角色统计信息的表格(游戏服务器)。我确定它可以在其他机器上工作,可能是不同的 php 版本。 有人可以为 php v5.2.1 调整此代码吗?

谢谢

【问题讨论】:

【参考方案1】:

您收到的错误消息中清楚地突出显示了您的问题。当您调用 sorting(1,$table); 时,变量 $table 尚未定义(如错误消息所述,这是第 38 行),因此当您的函数尝试运行第 12 行时:foreach($table as $entry) for 循环失败,因为 for- loop 只接受一个数组,而您要求它循环的是一个未设置或空值。

但我在另一个循环中设置了$table 变量,我听到你说!好吧,你试试看,但 PHPStorm 很有帮助地强调:

因为您假设查询已成功运行并且在此处还至少返回了一行:foreach ($dbh-&gt;query('SELECT TBL_CHARACTER.FLD_LEVEL, TBL_C....但永远不要检查您是否存在传递未实例化变量的风险。

那你能做什么?好吧,要么在尝试向其添加任何内容之前在某处声明您的 $table 变量,以便它始终至少是一个有效的结果。

更明智的是,虽然我会将您的查询从 foreach 中取出并将结果存储在某处,然后您可以检查您是否有任何数据并在没有任何数据时适当地处理这种情况,例如

$result = $dbh->query('SELECT TBL_CHARACTER.FLD_LEVEL, TBL_CHARAC....fetchAll()....

then say 
if(sizeof($result) > 0) 

     foreach($result as $row)
     \\\do all your stuff here
     
 else 
      //output something useful 

您的代码中其他一些看起来不寻常的事情是

$i++;
$table[$i-1]['level']=$row['FLD_LEVEL'];

你为什么要递增 $i,然后每次都减去 1?在最后做增量不是更有意义吗?但无论如何,你根本不需要做增量,因为你可以这样做:

$array = ['level' =>$row['FLD_LEVEL'],['character' => $row['FLD_CHARACTER'] ....];

 $table[] = $array;

然后它会自动被正确索引。这样做的唯一原因是如果您需要项目的特定索引,但我看不到您正在这样做

我也看不出使用这个有什么意义:

$n++;
if($n>=10) break;

您正在增加 $i 并且您正在增加 $n 它们都是相同的值,所以只需选择其中一个,或者不增加任何内容并说(假设您的结果在索引数组中并且您不获取密钥或任何东西)

foreach($result as $key => $row)

  if($key > 9) break;//because it starts at zero, key 9 = 10 iterations, so > 9 is our limit
  //sensibly building your array


简而言之,我认为这与 PHP 版本无关。但无论如何,你应该升级到 php7,虽然我很欣赏这可能不在你的控制范围内

【讨论】:

以上是关于如何构造一个合适的 foreach()的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Files.lines(...).forEach(...) 读取文件?

如何在 smarty 中找到 foreach 循环的最后一个索引

QTextEdit foreach

Swiftui foreach 内部参数

如何使用 foreach 和 doMC 包为随机模拟设置种子?

HelloCube:ForEach