我正在建立一个系统,它将对原始数据进行各种计算,并根据计算提供输出。
我的主要问题是更多建议而不是操作方法。
使用MySQL数据库和php访问。
目前需要完成约200种不同的计算,但这些计算属于4种计算类型,即一种计算类型是x除以y,而不同的计算将是x或y的不同原始值。
系统需要在系统的各个部分执行不同的计算,因此我创建了一个函数来执行计算。目前我有保存在数据库中的实际计算代码(带有一点点错误处理),就像这样;
**calc_id** | **calc_code**
aDIVb | if($primBVal != 0){ $result = ($primAVal / $primBVal);} else {$result = 'NA';}
aPERCb | if($primBVal != 0){ $result = (100 / $primBVal) * $primAVal;} else {$result = 'NA';}
等。
然后使用eval( $calcArray['calc_code']);
4个计算将永远不会改变,但将来可能会增加更多。
问题是,我应该将此代码构建到PHP函数中,还是可以按原样保留在数据库中?基于可以添加更多内容的事实,我倾向于数据库,因为我可以添加新行来处理新的计算类型,而不必编辑任何代码。
希望这一切都有道理,为长期问题道歉,可能是狡猾的格式化。
提前致谢。
答案 0 :(得分:2)
首先:除非有充分的理由,否则不要使用eval()
。 并且没有充分的理由 。
在最坏的情况下eval()
会使您的应用程序容易受到注入攻击,而且速度非常慢。一些研究揭示了为什么eval是一个大禁忌的充分理由。
如果你这样做并且想要从PHP切换到另一种语言,你的数据库中仍然会有PHP代码。这使得迁移语言变得非常困难。您应始终努力使应用程序的尽可能多的部分尽可能独立。
在这种情况下,您可以将您使用的语言与数据库紧密结合。这是一种不好的做法。
从数据库运行计算的唯一可能性是评估它们(这很糟糕,见上文)或者用字符串操作或正则表达式反汇编字符串会导致不必要的工作。
为了解决您的问题,您必须根据您需要的计算执行代码。这可以通过switch-case-statement或if-statements来完成。但这也不是一个非常优雅的解决方案。想象一下,在将来计算或扩展功能之前,您需要执行其他操作。您需要更新所有案例或if语句。
有一个很好的设计模式叫做Strategy Pattern。当一个用例可以被不同地处理时,策略模式可以解决问题,这可能是你想要的。
您想要计算某些内容(用例),并且有不同的计算类型(不同的策略)
要实施战略模式,您基本上需要三件事。
您的界面可能如下所示:
<?php
interface CalculatableInterface {
public function calculate();
}
界面将确保您的所有策略都提供实际运行计算的方法。没什么特别的。
接下来,您可能希望有一个基类,它将计算运算符作为构造函数参数并将它们存储到属性中。
<?php
abstract class Calculatable {
protected $valueA;
protected $valueB;
public function __construct($valueA, $valueB)
{
$this->valueA = $valueA;
$this->valueB = $valueB;
}
}
现在它变得严肃起来。我们正在实施我们的战略。
<?php
class Division extends Calculatable implements CalculatableInterface {
public function calculate()
{
return ($this->valueB != 0) ? $this->valueA / $this->valueB : 'NA';
}
}
class Percentage extends Calculatable implements CalculatableInterface {
public function calculate()
{
return ($this->valueB != 0) ? (100 / $this->valueB) * $this->valueA : 'NA';
}
}
当然你可以稍微清理一下这个,但我想在这里指出的是类声明。
我们正在扩展我们的Calculatable
类,以便我们可以通过构造函数传递算术运算,并且我们正在实现告诉我们班级的CalculatableInterface
:“嘿!你必须提供一个计算方法,我不在乎你是否愿意。
我们稍后会看到为什么这是模式的一个组成部分。
所以我们有两个具体的类,它们包含实际算术运算的实际代码。如果您需要,您可以轻松地更改它,如您所见。 要添加更多操作,只需添加另一个类。
现在我们将创建一个可以注入策略的类。稍后您将实例化此类的对象并使用它。
以下是它的样子:
<?php
class Calculator {
protected $calculatable;
public function __construct( CalculatableInterface $calculatable )
{
$this->calculatable = $calculatable;
}
public function calculate()
{
return $this->calculatable->calculate();
}
}
这里最重要的部分是构造函数。看看我们如何键入 - 提示我们的界面。通过这样做,我们确保只能注入一个对象(Dependency Injection),其类实现接口。我们不需要在这里要求具体的课程。这是关键点。
那里还有一种计算方法。它只是我们执行它的计算方法的策略的包装。
所以现在我们只需要创建一个Calculator
类的对象,并传递一个策略类的对象(包含算术运算的代码)。
<?php
//The corresponding string is stored in your DB
$calculatable = 'Division';
$calc = new Calculator( new $calculatable(15, 100) );
echo $calc->calculate();
尝试将$calculatable
中存储的字符串替换为Percentage
,您会看到将执行计算百分比的操作。
策略模式允许您创建一个干净的界面来处理动态任务,这些任务只在运行时具体化。您的数据库既不需要知道我们如何计算事物,也不需要知道您的实际计算器。我们唯一需要确保的是针对接口的代码,它提供了一种让我们计算事物的方法。
答案 1 :(得分:0)
如果我是你,我不会把计算php放在数据库中。为什么?假设您决定用另一种语言编写系统,您需要在db中解析php代码,并将其转换为新的语言细节(这是最糟糕的情况)。如果我是你,我会将其转换为服务,并将其分成几部分。您可以将每个调用放入作业队列,在作业完成后,您可以将结果保存在db中。您可以将此服务用于多种类型的客户端。
您可以为每个计算创建函数,以便轻松更改计算算法。此外,您可以添加新计算作为功能。
答案 2 :(得分:0)
如果我理解你的问题,你就会得到一个包含域数据的数据库,以及你对这些数据执行的大量计算。目前,您将这些计算存储为数据库中的字符串,并使用eval()
执行这些计算。
我可以想象这样做有一些原因 - 在不同的计算实例之间共享计算很容易(因此您可以运行多个并行计算,或创建新的计算客户端(例如,Web客户端,命令行客户端,移动应用程序)。它还使管理计算相当容易 - 它们都生活在一个地方。
然而,有一些明显的缺点:
所以,你有很多选择。在类似的场景中,我经常在我的应用程序结构中创建一个包含计算的文件夹,并使用文件流动态加载计算代码。通过使用具有自动部署的源代码控制系统,您可以将其部署到任意数量的计算实例。
对于更复杂的场景,我构建了一点domain specific language。这完全是possible in PHP。在您的情况下,这将允许您删除大量的内务处理逻辑($primBVal != 0
)并专注于域。这是非常重要的,但如果你有数百个计算,那么它可能是值得的。
答案 3 :(得分:0)
我经营一个市场研究网站,其中确实需要完成许多计算,主要是绩效指标。我的经验和我的实际工作告诉我你应该使用PHP脚本而不是数据库字符串,即时添加。这是因为您有一个工作流程,可以通过移动和删除代码片段来更好地管理。数据库应该可以很好地用作工作流程。经理或过程至关重要。