1. 程式人生 > >記兩次迴圈語句中陣列、變數未宣告(未銷燬)導致的bug

記兩次迴圈語句中陣列、變數未宣告(未銷燬)導致的bug

上個月稀裡糊塗的犯了兩次差不多的問題.....特記下,以示警醒。

第一次:悲催的改了三次程式碼...

根據特定條件,列印curl語句,然後放到 .sh檔案中,用Shell來執行。

查詢表***,根據產品id和結束時間(大於當前時間)查詢使用者。通過介面執行特定語句(就是我打印出來的語句)。

第一次程式碼:

$config = array(
	array(1,2,3,4),
	array(5,6,7,8)
	);
foreach ($config as $item) {
	$sql = "select * from (select userid,enddate from tablename where id in (?,?,?) and enddate > now() order by enddate desc) as a group by userid";
	$sth = DB_Pdo::instance()->get_dbh()->prepare($sql);
	$sth->execute(array($item[0],$item[1],$item[1]));
	$arr = $sth->fetchAll(PDO::FETCH_ASSOC))
	$sth = null;
	foreach ($arr as  $value) {
		echo "curl '連結(此處省略)&sid=".$item[3]."&enddate=".$value['enddate']."&userid=".$value['userid']."'\n";
	}
}

這個程式碼在程式碼層面是沒問題的,但是當資料量比較大的時候就會出現問題了,巢狀的sql語句執行起來很耗費時間、資源,可能會導致宕機。因此廢棄,換一種方式。 ......... 悲劇即將到來。

第二次程式碼:

$config = array(
	array(1,2,3,4),
	array(5,6,7,8)
	);
$userid_arr = array();
foreach ($config as $item) {
	$sql = "select userid,enddate from tablename where id in (?,?,?) and enddate > now() order by id";
	$sth = DB_Pdo::instance()->get_dbh()->prepare($sql);
	$sth->execute(array($item[0],$item[1],$item[1]));
	while (false !== $row = $sth->fetch(PDO::FETCH_ASSOC)) {
		if($userid_arr[$row['userid']] < $row['enddate']){
			$userid_arr[$row['userid']] = $row['enddate'];
		}
	}
	$sth = null;
	foreach ($userid_arr as $key => $value) {
		echo "curl '連結(此處省略)&sid=".$item[3]."&enddate=".$value."&userid=".$key."'\n";
	}
}

上邊程式碼,改了sql語句,但是用到了迴圈。。。大眼一看,好像沒問題,但是當執行的時候就會發現,curl語句比第一次程式碼執行出來的要多一部分。然後才發現迴圈語句中的 $userid_arr 是在foreach外面宣告的,也就是說foreach迴圈第二次的時候$userid_arr陣列內依然包含第一次迴圈後的結果,此時並不是空陣列......然後第二次foreach的時候會把第一次迴圈過的資料再次迴圈。。。

所以又改了第三次,將$userid_arr = array(); 移到while上面,這樣每次foreach的時候都會執行 userid_arr = array()

做迴圈的時候,遇到陣列要麼在之前宣告,要麼就在底部銷燬。。。切記切記。。。然鵝。峩還是莫記得......不過這次是變數,不是陣列了.........

 

第二次犯的錯誤和第一次類似

指令碼程式碼大體上就是這樣(程式碼過長,就縮略一下)

while(1){
    $result = 從佇列取出來的資料;
    if(! $result){
        echo "*";
        sleep(1);
    }elseif($result){

        處理 $result 資料;
        *
        *
        *
        *
        *一大堆程式碼(省略)···

        if(isset($result['appflag']) && isset($result['appid'])){
            $appflag = $result['appflag'];
            $appid = $result['appid'];
        }
        
        *
        *
        *
        *
        *又一大堆程式碼(省略)···
        
        if($appflag && $appid){
             危險程式碼........
        }
    }
}

$result 是從kafka取出來的陣列,但是資料還不一樣,有些包含了 $result['appflag'] 和 $result['appid']。。 有些陣列則沒有這兩項。這就是噩夢的開端,執行了之後,發現。。。唉~~~ 沒有包含$result['appflag'] 和 $result['appid']的資料,也執行了“危險程式碼”。仔細檢查發現:if($appflag && $appid) 並未生效,看了下發現是while迴圈,當運行了一次包含了 $result['appflag'] 和 $result['appid']的資料後,$appflag 、 $appid 這兩個變數就一直存在了.....再迴圈的時候 $appflag && $appid 就一直為true了,程式碼也就一直執行了。

程式碼長並不是未宣告$appflag 和 $appid 的藉口,幸好及時發現,在執行完“危險程式碼”後,增加銷燬$appflag 、 $appid 兩個變數的程式碼,直接unset掉。。。或者程式碼中一直使用$result['appflag'],$result['appid'] 不做賦值操作,也不會出現這種問題。

 

總之總之,迴圈操作一定要倍加小心,用到陣列要宣告,用到迴圈內用到判斷一定要仔細看下條件是否需要做處理。。。

切記,以上。