iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 4
4

Why
為什麼 PHP 可以幫我們解決重複性的工作呢?
因為它有一個很強大的功能:迴圈
它能幫你把重複的事情一行一行做完,任勞任怨。

How
怎麼使用呢?來舉一個例子:

假設我們遇到了一個頭痛的對帳問題。
在商城中有6000筆訂單成立,總金額約有90萬
但是黑貓物流商告訴我們只有收到約70萬貨款
並附上一份試算表說明狀況。
我們如果要人工比對出到底少了哪些訂單
哪些訂單沒收到錢,有沒有金額錯誤少收錢的狀況
用人工比對那一定會耗掉數日光陰
看到脫窗還不一定正確

這就展現技術價值的最佳時機了
自告奮勇跳出來用 PHP 來解決問題
幫小助理妹妹省下三四天的盯電腦的痛苦時間
對你的態度一定會不一樣
讓我們來看是怎麼做到的

假設這是系統內的訂單我們縮小簡化到 從部分單號來舉例分析

$order_total = array();
$order_total['1221000'] = 100;  
// 1221000 是訂單編號, 100 是訂單金額,以下以此類推;
$order_total['1221001'] = 200;  
$order_total['1221002'] = 300; 
$order_total['1221003'] = 200;
$order_total['1221004'] = 250;
$order_total['1221005'] = 150;
$order_total['1221006'] = 300;
$order_total['1221007'] = 250;
$order_total['1221008'] = 330;

這是黑貓貨到付款代收貨款的金額

$order_receive = array();
$order_receive['1221000'] = 100; 
// 1221000 是訂單編號, 100 是黑貓貨到付款代收金額;
$order_receive['1221001'] = 0;
$order_receive['1221002'] = 300;
$order_receive['1221003'] = 200;
$order_receive['1221004'] = 250;
$order_receive['1221005'] = 150;
$order_receive['1221006'] = 300;
$order_receive['1221008'] = 0;
$order_receive['1130199'] = 200; 

What

  • array() 這個新語法是陣列的意思,陣列就像是一列火車,一節一節載著資料
  • 整行的意思是告訴電腦 $order_total 這個變數是一列火車陣列
  • 那這行 $order_total['1221000'] = 100; 的意思是這節車廂名字是 1221000 裡面裝著資料 100

那對帳的邏輯程式語法要怎麼寫呢?

$order_not_exist = array();  
// 這個陣列我們預計拿來裝黑貓收款列表中不存在的訂單編號
$order_zero = array();       
// 這個陣列我預計拿來裝黑貓代收款,對方不取貨不付款的單號
foreach($order_total as $order_id => $order_total) { // *
  if(isset($order_receive[$order_id])){
      // 如果這一筆訂單在黑貓的代收貨款列表中存在
      if($order_receive[$order_id] == $order_total){ 
          // $order_receive[$order_id] 可從這個陣列取出代收款金額
          // 如果這張單有收到貨款,就是對帳成功,兩邊都有相同的金額我們不需紀錄
      }else{
          // 沒收到貨款但是存在編號的訂單
          $order_zero[] = $order_id; // 把沒收錢的單號塞到陣列裡記著
      }
  }else{
      // 如果這一筆訂單不存在
      $order_not_exist[] = $order_id; // 把消失的單號塞到這個陣列裡記著
  }
  // 到這裏會跳到上面星號 * 取下一筆訂單在拿出 order_id 與 order_total 來比對
}
// 跑完這個迴圈我們把結果印出來
echo "沒收到貨款的訂單\n";
print_r($order_zero);
echo "黑貓列表中不存在的訂單\n";
print_r($order_not_exist);

今天的課後作業是怎麼找出另一種情況,如果黑貓的貨款列表包含上個月訂單
想要排除掉,不然實際營業很難計算,那要怎麼做呢?

想真的執行 PHP 語法的話,可以到這個網址把問題複製上去,就可以看到答案了。
http://sandbox.onlinephpfunctions.com/


上一篇
Day 3. PHP教學: 一分鐘搞懂『如果...就...』的 if else 語法
下一篇
Day 5. PHP教學: 開始架設自己的遊戲攻略網站 (class 物件篇)
系列文
寫給朋友的 PHP 從 0 到 100 實戰教程30
0
rules
iT邦新手 5 級 ‧ 2018-01-11 16:58:48

請問這些小題目有參考答案嗎?

看更多先前的回應...收起先前的回應...

有哦 我變出來

放到下一篇文章的開頭囉

rules iT邦新手 5 級‧ 2018-01-12 14:48:38 檢舉

有看到了,謝謝您

請問如果黑貓的貨款列表包含去年這個月的訂單,答案的演算法應該會誤抓這個同月不同年的訂單嗎?謝謝!而且答案中的訂單編號只排到三位數,那假設一天的訂單量超過一千筆怎麼辦?感恩!

沒錯哦,所以要設計一個儲存日期跟訂單的新方法來避開這個問題!
這是一個拿來思考的好題目不是嗎?哈哈
真實世界的訂單編號,會加上英文跟五位數來處理當日的訂單,甚至會用到微秒跟亂數來避開重複問題,可以搜尋掏寶雙十一他們在處理幾秒鐘上千萬筆訂單想了很多方法來處理這件事。

0
h223449961
iT邦新手 5 級 ‧ 2018-04-01 15:25:13

請問如果黑貓的貨款列表包含去年這個月的訂單,答案的演算法應該會誤抓這個同月不同年的訂單嗎?謝謝!而且答案中的訂單編號只排到三位數,那假設一天的訂單量超過一千筆怎麼辦?感恩!

疑 跟上面同一題哦!

0
david828107073
iT邦新手 3 級 ‧ 2018-06-01 12:55:41

感謝您的文章,看過前幾課都淺顯易懂、生動有趣,但這課開始不太懂XD。

foreach($order_total as $order_id => $order_total) { // *
  if(isset($order_receive[$order_id])){
      // 如果這一筆訂單在黑貓的代收貨款列表中存在
      if($order_receive[$order_id] == $order_total){ 
          // $order_receive[$order_id] 可從這個陣列取出代收款金額
          // 如果這張單有收到貨款,就是對帳成功,兩邊都有相同的金額我們不需紀錄
      }else{
          // 沒收到貨款但是存在編號的訂單
          $order_zero[] = $order_id; // 把沒收錢的單號塞到陣列裡記著
      }
  }else{
      // 如果這一筆訂單不存在
      $order_not_exist[] = $order_id; // 把消失的單號塞到這個陣列裡記著
  }
  
  裡面 isset  , $order_total as $order_id => $order_total 不太懂這些用法
看更多先前的回應...收起先前的回應...

好哦 我調整看看

感謝你提供這麼優質的系列文,可能我太笨看不懂.

感謝你提供這麼優質的系列文,可能我太笨看不懂.

相信我,你現在就夠聰明了,是我沒寫清楚 哈哈哈

0
W
iT邦新手 5 級 ‧ 2018-06-07 04:51:57

您好,依據您提供的作業答案嘗試解題,我好像還是遇到一些小問題,
裡面第二層的foreach會有如下錯誤:

<br />
<b>Warning</b>:  Invalid argument supplied for foreach() in <b>[...][...]</b> on line <b>35</b><br />

可否請您協助解惑:
http://sandbox.onlinephpfunctions.com/code/8701e690dfa8e269d4e64b5d8fab0bf2a2507b65
謝謝!

看更多先前的回應...收起先前的回應...
foreach($order_total as $order_id => $order_total){
}

$key => $value 這邊新變數命名蓋到初始的陣列 $order_total
XDD 初始陣列的命名可以改一下

我這裡有一個除錯的方法給你 把其他無關的東西都註解掉
把看起來很複雜的問題切小,單純化,就很容易發現問題了

也可以搭配

print_r($order_total);
die; // 這行會強制結束,後面的都不執行

確認這個變數是你預期中的資料

W iT邦新手 5 級‧ 2018-06-10 10:00:14 檢舉

謝謝說明!我自己試著修改程式碼後有跑出理想結果了。
...所以請問意思是您文章中這樣寫是一個陷阱題嗎XD

foreach($order_total as $order_id => $order_total){
}

關於除錯小撇步分享很受用!謝謝~
從您的文章受益良多,很喜歡您用遊戲比喻的方式,讓一切變得生動有趣XD

的確是陷阱 XD

8
rainbowrain
iT邦新手 5 級 ‧ 2018-07-12 16:32:10

剛開始看這系列文章,底子是C#入門程度
有些自己乍看不懂的部份分享一下順便自己做個整理

先來講 array 跟 foreach
array就是falconwei老師在文章開頭建立的兩組數據 $order_total 及 $order_receive
如果有一些程式基礎,常見的array可能是像這樣

$numbers = [1,2,3,5,8,1]

這就是一個數字的array

$words = ["a","bc","def","abc"]

這就是一個字串的array

要從這樣的array取值靠的是index(值在array中的位置,從0開始)
$numbers[3] -> 5
$words[2] -> "def"

而falconwei老師的array中放的叫keyValue,內容長的像這樣
$order_total = ['1221000'=> 100,'1221001' => 200, '1221002' => 300,'1221003' => 200,'1221004' => 250]
'1221000' => 100就是一組keyValue,'1221000'是key,100是這個key對應的value
要從這樣的array取值靠的是key
$order_total['1221000'] -> 100

接下來是foreach

foreach有至少兩種
1. foreach(變數1 as 變數2)
foreach就是要把集合中的所有物件一個個叫出來看
變數1放的就是你要看的那個集合
在falconwei老師的例子中我們要看的就是$order_total
而變數2是值,就是array中的物件

    #以numbers為例子
    foreach($numbers as $num){
    echo $num.",";
    }
    // 1,2,3,5,8,1,
    
    #以order_total為例子
    foreach($order_total as $num){
    echo $num.",";
    }
    // 100,200,300,200,250,150,300,250,330,

$numbers列出來的是array中每個位置的值
$order_total列出來的是array中每個key的value

2. foreach(變數1 as 變數2 => 變數3)
在falconwei老師的程式中

foreach($order_total as $order_id => $order_total) { /*do something*/ }

變數1一樣是我們要看的集合
變數2代表的是index或key
變數3代表的是值

然後這行程式是個陷阱,本來用來裝order單集合的$order_total被用來裝別的東西了
有三個變數的foreach執行結果如下

    #以numbers為例子
    foreach($numbers as $index => $value){
    echo $index.":".$value.",";
    }
    // 0:1,1:2,2:3,3:5,4:8,5:1,
    
    #以order_total為例子
    foreach($order_total as $key => $value){
    echo $key.":".$value.",";
    }
    // 1221000:100,1221001:200,1221002:300,1221003:200,1221004:250,1221005:150,1221006:300,1221007:250,1221008:330,

從輸出結果可以知道
如果array的內容是數字或字串
那變數2代表的是位置(index),變數3是那個位置放的值(value)
如果array的內容是keyValue
那變數2代表的是鍵(key),變數3是那個鍵對應的值(value)

如果能預期下面這段程式出來的結果,那應該這部份算是搞懂了

    foreach($order_total as $value => $key){
    echo $key.":".$value.",";
    }

課後作業的話
從$order_total的結構可以判斷每個keyValue中的key就是單號,前4碼是日期
所以在foreach中先行判斷日期是否符合你要查詢的條件
應該是抓substring之類出來比對
是的話就繼續做後面的動作,不是的話就跳過換下一個keyValue

看更多先前的回應...收起先前的回應...

謝謝你的回覆,不然這篇真的完全看不懂(零基礎菜鳥

超棒

謝謝你及老師的回饋~

感謝這篇!
不然跳太快,還真得看不懂

2
murasaki1220
iT邦新手 5 級 ‧ 2018-09-20 17:42:57

謝謝falconwei老師撰寫這一系列生動易懂的php教學,讓我這樣的零基礎菜鳥也能看懂。
我的問題跟程式比較無關,跟解題邏輯比較有關。

在我看來,問題的解法有賴於釐清下列兩點

  1. 有收款、沒訂單編號
  2. 有訂單編號、沒收款

我可以理解為什麼要做2 (90萬跟70萬的差額),
但想不通為什麼要做1...

感謝您的答覆,如果問題很蠢請見諒。

因為現實中,物流或是系統/人可能會出錯,把其他商家的訂單混入。
你的問題很棒,剛開始寫就知道要問這個實務上的問題!給你個讚

我要留言

立即登入留言