2012-01-25 179 views
-1
$amnt = "1.00"; 
$from = "USD"; 
$to = "GBP"; 
/* Set up new DB object with the from/to currency */ 
$DBob = new database($from, $to); 
$locFrom = $DBob->readLocation($from); 
$locTo = $DBob->readLocation($to); 
echo $locFrom . $locTo; 

兩個對象的echo返回值相同,對於$ to變量......而不是在SQL中返回兩個單獨的查詢。該查詢是一樣的,但是一個使用從貨幣代碼$和其它使用$貨幣代碼重複的返回值php

SQL代碼:

public function readLocation($toFrom) 
{ 
    //establish a connection to the mysql database 
    $dbcon = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME) OR DIE ('Could not connect to Mysql database: '. mysqli_connect_error()); 
    if ($toFrom == 'from') 
    { 
     //$substring1 = substr($this->fromcurr,0,2);// 
     $query2 = ("SELECT location AS loc FROM currency WHERE countrycode ="."'$this->fromcurr'"); 
    } 
    elseif ($toFrom == 'to'); 
    { 
     //$substring1 = substr($this->tocurr,0,2);// 
     $query2 = ("SELECT location AS loc FROM currency WHERE countrycode ="."'$this->tocurr'"); 
    } 
    $result = mysqli_query($dbcon,$query2); 
    $resultR = mysqli_fetch_array($result); 
    mysqli_close($dbcon); 
    $queryResult = $resultR['loc']; 
    return $queryResult; 
} 
+0

我們應該「知道」readLocation()是做什麼的?黑盒代碼不利於調試... –

+0

請顯示$和$ to。 – ZeroSuf3r

+2

由於在那裏沒有真正的問題,我會用我瘋狂的想象力來確定你真的想問問獨角獸是否存在。我會回答:「只要你相信,馬克,只要你相信。」*** – rdlowrey

回答

0

你搞砸功能的代碼,因此它不工作。我強調了一些關於如何改進它的問題,這將幫助您不僅可以刪除錯誤,還可以通過更改編寫代碼的方式來防止將來出現類似錯誤。

在本次討論中,我將一些適當的值編碼放在一邊,這會導致缺陷和缺陷(SQL入侵)。只是說,你應該自己添加這些。

該函數的主要業務是構建條件SQL查詢並執行它。所以首先移動查詢大樓出來的功能到它自己的功能:

private function buildReadLocationSQL($countrycode) 
{ 
    $SQLPattern = "SELECT location AS loc FROM currency WHERE countrycode = '%s'"; 
    return sprintf($SQLPattern, $countrycode); 
} 

然後,你需要找出$countrycode應該是什麼。您在這裏使用兩個字符串值來描述您需要的內容。爲什麼不把名字命名呢?

public function readLocationFrom() 
{ 
    ... 
} 

public function readLocationTo() 
{ 
    ... 
} 

在這裏有兩個函數,很明顯他們做了什麼,當你調用(調用)它們時你不會犯任何錯誤。

缺少的部分是封裝數據庫連接和查詢。這是有道理的,因爲一旦你的應用程序運行而不是每個查詢,你只想連接到數據庫。連接到數據庫非常昂貴。此外,這有助於通過使代碼更加模塊化來擴展您的課程。

因此,讓我們稍微改變一下數據庫類,使它存儲連接(不需要明確地關閉它),並提供一個函數來查詢數據庫:

class Database 
{ 
    private $connection; 
    private function connect() 
    { 
     $connection = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); 
     if ($connection === FALSE) 
     { 
      throw new RuntimeException(sprintf('Could not connect to Mysql database: %s', mysqli_connect_error())); 
     } 

     $this->connection = $connection; 
    } 
    private function query($sql) 
    { 
     if (!$this->connection) $this->connect(); // lazy connect to the DB 
     $result = mysqli_query($this->connection, $sql); 
     if (!$result) 
     { 
      throw new RuntimeException(sprintf('Could not query the Mysql database: %s', mysqli_error($this->connection))); 
     } 
     return $result; 
    } 
    ... 
} 

這兩個新的私有函數關心數據庫特定的連接和查詢作業。隨着時間向數據庫類添加越來越多的功能,您可以輕鬆地重新使用它們。另外這兩個是私有的(作爲$connection成員),因爲你要隱藏來自應用程序的其餘細節。

現在需要將其與readLocationFromreadLocationTo函數放在一起以使其起作用。由於這兩個函數都做類似的事情,所以我們創建了另一個封裝兩者的私有函數,它與原始函數邏輯類似。

然而,這一次,我們要小心,傳遞的參數僅包含意義(前置條件檢查)值。另外,功能是私有的,所以它無法通過減少調用它錯誤從類之外的可能性,其他代碼調用(它不能從外部調用):

private function readLocationConditional($what) 
{ 
    switch($what) 
    { 
     case 'from': 
      $countrycode = $this->fromcurr; 
      break; 

     case 'to': 
      $countrycode = $this->tocurr; 
      break; 

     default: 
      throw new InvalidArgumentException(sprintf('Invalid value for $what ("%s").', $what)); 
    } 

    $sql = $this->buildReadLocationSQL($countrycode); 
    $result = $this->query($sql); 
    $array = mysqli_fetch_array($result); 
    $field = 'loc'; 
    if (!isset($array[$field])) 
    { 
     throw new UnexpectedValueException(sprintf('Row does not contain %s (contains %s)', $field, implode(',', array_keys($array)))); 
    } 
    $location = $array[$field]; 
    return $location; 
} 

所以,讓我們仔細查看與原始函數做了什麼不同之處:輸入值經過驗證,條件變量分配給$countrycode。這有助於將事情分開。如果給出$what的某個「未定義」值,則拋出異常。如果您錯誤地使用了此功能,將立即通知您。

然後新的buildReadLocationSQL函數用於創建SQL,新的query函數用於運行查詢。最後,從數據庫返回的數據會再次進行驗證,如果缺少所需字段,則會引發異常。如果返回的數據有問題,這將立即通知您。

這是現在很容易與兩個新的公共功能,這是新的專用功能readLocationConditional實際包裝彙集。因此,讓我們把這一切放在一起:

public function readLocationFrom() 
{ 
    return $this->readLocationConditional('from'); 
} 

public function readLocationTo() 
{ 
    return $this->readLocationConditional('to'); 
} 

所以,現在,你已經重寫了數據庫類,使它更靈活,更好的運作。把它放在一起,就是這樣。

這裏的第一個關鍵點是,你檢查錯誤情況正常。我使用異常而不是die,因爲我認爲這對開發人員更友好。您可以使用die語句或錯誤值等來執行此操作。但例外情況不僅會告訴您一條消息,還會發現發生了什麼事情,可以被捕獲(您無法捕獲die),並且可能具有不同的類型,所以如果出現問題,他們會攜帶更多有用的信息。

第二個關鍵點是,您簡化代碼。代碼流越簡單,編碼越容易。把涵蓋它的東西放到它自己的功能中是非常有效的。你可以在你分開的時候繼續寫下它們。另一個提示:一個函數具有的參數越少(理想情況下:零不總是可能的),你可以做的錯誤越少,你需要驗證的輸入值越少。

只是說:你本來這在某種程度上爲好,但不完全。你只有一個地方檢查錯誤(連接到mysql數據庫),但不是查詢本身,而是查詢返回值而不是函數參數。把所有東西都放到它自己的小函數中,可以更容易地看到要檢查和處理細節。

最後但並非最不重要的,新的使用,我所做的名字更講(NSTDØ簡稱evrthng):

$amount = "1.00"; 
$currencyFrom = "USD"; 
$currencyTo = "GBP"; 

$db = new Database($currencyFrom, $currencyTo); 

echo $db->readLocationFrom(), $db->readLocationTo(); 

希望這有助於。只要有助於防止錯誤(這是您的代碼,將它用作您的工具)並考慮到模塊性,不要害怕編寫更多代碼。最後你會看到,這是更少的代碼和更少的麻煩。尋找你犯錯誤的實際部分也是一個很好的起點。


討論錯誤;我已經看到了以下情況:

elseif ($toFrom == 'to'); 
         ^

If -blocks可以艱鉅,結構調整你的代碼在這裏幫助。減少使用if,尤其是elseif。將零件移動到它自己的功能有助於降低複雜性。更少的複雜性,更少的錯誤(我們是人類)。

$query2 = ("..."); 
     ^ ^

這個括號是多餘的,可能是剛剛從前一個函數調用複製代碼的符號。多加小心。

只要把手指放在這些錯誤上,不會顯示整個圖片,只是修復那些不會讓你更進一步。所以最好是認清錯誤,理解錯誤的原因,然後思考如何防止錯誤。

0

看起來無論這個代碼是應該做的(這不完全清楚),它沒有被正確使用。看看一些重要的部分:

$from = "USD"; 
$to = "GBP"; 

後...

$locFrom = $DBob->readLocation($from); 
$locTo = $DBob->readLocation($to); 

,並在該函數內部...

if($toFrom == 'from') { 
    //... 
} 
else if($toFrom == 'to'); { 
    //... 
} 

的是,條件是永遠不會滿足。通過兩次調用函數,$toFrom函數參數(這不是特別直觀的變量名)被設置爲「USD」和「GBP」。它是從來沒有等於條件假定的「from」或「to」。

因此$query2從來沒有設置任何東西。這將導致我相信,此行的行爲是錯誤的或不確定的:

$result = mysqli_query($dbcon,$query2); 

更好的變量/函數名可能會幫助你引向邏輯使用任何的這個代碼是應該做的事情。但就目前而言,函數假設調用代碼沒有提供的值。如果該函數將假定這些值,它應該做的第一件事是檢查其輸入:

if (($toFrom != 'to') && 
    ($toFrom != 'from')) { 
    // Incorrect argument(s) supplied. 
    // Throw an error and do not proceed with the function 
}