$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;
对于$ to变量,两个对象的echo返回返回相同的值,而不是在SQL中返回两个单独的查询。查询是相同的,但是使用$ from货币代码而另一个使用$ to货币代码
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 :(得分:0)
看起来这个代码假设要做什么(这不是完全清楚的),它没有被正确使用。看看一些重要的部分:
$from = "USD";
$to = "GBP";
...后
$locFrom = $DBob->readLocation($from);
$locTo = $DBob->readLocation($to);
并在该功能内...
if($toFrom == 'from') {
//...
}
else if($toFrom == 'to'); {
//...
}
永远不满足条件。 $toFrom
函数参数(不是特别直观的变量名称)被设置为" USD"和" GBP"用两个函数调用。 永远不会等于"来自"或"到"作为条件假设。
所以$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
}
答案 1 :(得分:0)
你弄乱了函数的代码,所以它不起作用。我将重点介绍如何改进它,这不仅可以帮助您删除错误,还可以通过更改编写代码的方式来防止将来出现类似错误。
在这个讨论中,我将正确的值编码主题放在一边,这可能导致缺陷和缺陷(SQL inection)。只是说,你应该自己添加它们。
该函数的主要业务是构建条件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()
{
...
}
在这里有两个功能,它清楚他们做了什么,当你调用(调用)它们时你不会犯任何错误。
缺少的部分是封装数据库连接和查询。这是有道理的,因为您只想在应用程序运行而不是每个查询时连接到数据库。连接数据库很昂贵。此外,这有助于通过使代码更加模块化来扩展您的类。
因此,让我们稍微更改数据库类以使其存储连接(您也不需要显式关闭它,PHP将在脚本结束时为您执行此操作)并提供查询数据库的函数:
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
语句或错误值等来执行此操作。但例外不仅会告诉您一条消息,而且还会发生某些事情,可以捕获(您无法捕获{{1并且可以有不同的类型,因此如果出现问题,它们会传递更多有用的信息。
第二个关键点是您简化了代码。代码流越简单,代码就越容易。把覆盖它的东西放到它自己的功能中是非常有效的。您可以随意编写它们,同时保持分离。另一个提示:函数具有的参数越少(理想情况下:零,这并不总是可能),您可以做的错误越少,您需要验证的输入值就越少。
只是说:你最初也是以某种方式做到了这一点,但并非如此。您只有一个地方检查错误(与mysql数据库的连接),但不是查询本身,不是查询的返回值而不是函数参数。将所有内容放入其自身的小功能中,可以更轻松地查看要检查和处理细节的内容。
最后但并非最不重要的是,新用法,我更多地说出了名字(nstd o abbr evrthng):
die
希望这会有所帮助。并且不要害怕编写更多代码行,只要它有助于防止错误(它是您的代码,将其用作工具)并考虑到模块化。最后,您将看到这是更少的代码和更少的麻烦。寻找你犯了错误的实际部分也是一个很好的起点。
讨论错误;我见过以下内容:
$amount = "1.00";
$currencyFrom = "USD";
$currencyTo = "GBP";
$db = new Database($currencyFrom, $currencyTo);
echo $db->readLocationFrom(), $db->readLocationTo();
elseif ($toFrom == 'to');
^
- 块可能令人生畏,重构代码会有所帮助。减少使用If
,尤其是if
。将零件移动到它自己的功能中有助于降低复杂性。更少的复杂性,更少的错误(我们是人类)。
elseif
这个括号是多余的,可能只是复制上一个函数调用的代码。多加小心。
只要把手指放在这些错误上就不会显示整个图片,只是修复那些不会让你更进一步。因此,最好先识别错误并理解错误原因,然后再考虑如何预防错误。