在代码或数据库中保存计算?

时间:2014-03-07 12:15:01

标签: php mysql

我正在建立一个系统,它将对原始数据进行各种计算,并根据计算提供输出。

我的主要问题是更多建议而不是操作方法。

使用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']);

在php中计算这些值

4个计算将永远不会改变,但将来可能会增加更多。

问题是,我应该将此代码构建到PHP函数中,还是可以按原样保留在数据库中?基于可以添加更多内容的事实,我倾向于数据库,因为我可以添加新行来处理新的计算类型,而不必编辑任何代码。

希望这一切都有道理,为长期问题道歉,可能是狡猾的格式化。

提前致谢。

4 个答案:

答案 0 :(得分:2)

Eval是邪恶的

首先:除非有充分的理由,否则不要使用eval() 并且没有充分的理由

在最坏的情况下eval()会使您的应用程序容易受到注入攻击,而且速度非常慢。一些研究揭示了为什么eval是一个大禁忌的充分理由。

不要将计算代码保存到数据库

如果你这样做并且想要从PHP切换到另一种语言,你的数据库中仍然会有PHP代码。这使得迁移语言变得非常困难。您应始终努力使应用程序的尽可能多的部分尽可能独立。

在这种情况下,您可以将您使用的语言与数据库紧密结合。这是一种不好的做法。

从数据库运行计算的唯一可能性是评估它们(这很糟糕,见上文)或者用字符串操作或正则表达式反汇编字符串会导致不必要的工作。

关于Strategy

的全部内容

为了解决您的问题,您必须根据您需要的计算执行代码。这可以通过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脚本而不是数据库字符串,即时添加。这是因为您有一个工作流程,可以通过移动和删除代码片段来更好地管理。数据库应该可以很好地用作工作流程。经理或过程至关重要。