你搞砸功能的代碼,因此它不工作。我強調了一些關於如何改進它的問題,這將幫助您不僅可以刪除錯誤,還可以通過更改編寫代碼的方式來防止將來出現類似錯誤。
在本次討論中,我將一些適當的值編碼放在一邊,這會導致缺陷和缺陷(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
成員),因爲你要隱藏來自應用程序的其餘細節。
現在需要將其與readLocationFrom
和readLocationTo
函數放在一起以使其起作用。由於這兩個函數都做類似的事情,所以我們創建了另一個封裝兩者的私有函數,它與原始函數邏輯類似。
然而,這一次,我們要小心,傳遞的參數僅包含意義(前置條件檢查)值。另外,功能是私有的,所以它無法通過減少調用它錯誤從類之外的可能性,其他代碼調用(它不能從外部調用):
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 = ("...");
^ ^
這個括號是多餘的,可能是剛剛從前一個函數調用複製代碼的符號。多加小心。
只要把手指放在這些錯誤上,不會顯示整個圖片,只是修復那些不會讓你更進一步。所以最好是認清錯誤,理解錯誤的原因,然後思考如何防止錯誤。
我們應該「知道」readLocation()是做什麼的?黑盒代碼不利於調試... –
請顯示$和$ to。 – ZeroSuf3r
由於在那裏沒有真正的問題,我會用我瘋狂的想象力來確定你真的想問問獨角獸是否存在。我會回答:「只要你相信,馬克,只要你相信。」*** – rdlowrey