如何重构我的代码以将公式计算的关注点与记录中间公式值分开?

时间:2017-08-08 14:34:51

标签: php logging refactoring single-responsibility-principle

我正在寻找具体的重构建议。

首先,我有一个只有计算而没有输出的脚本。我想编写计算输出,以便在屏幕上看到公式及其实际公式值。

所以我实现了一个DEBUG变量并添加了输出语句,以显示DEBUG值为true的时间。我的问题是我的输出代码最终与计算紧密耦合。

我的代码现在看起来像这样:

$rows = db_query("select..*");
foreach($rows as row)
{
    $description = $row['model'];

    //dump() prints output on screen
    if ($this->DEBUG) dump("<h1>Trying {$description}...</h1>");

    if ($this->DEBUG) dump("Checking Speed . . . ");
    $this->calcSpeed();

    if ($this->DEBUG) dump("Checking Flow . . . ");
    $this->checkFlow();
}

然后在calcSpeed内部,我有计算和输出:

$this->ratio = $this->r / $this->q;
$this->n = ($factor * $this->vel);
$this->t = $this->n * pow($this->r, 0.5) / pow(($this->reject * 2), 0.75);
$this->p = $this->n * pow($this->q, 0.5) / pow(($this->feed * 2), 0.75);

if ($this->DEBUG) dump("<b>Computing Speed</b>");
if ($this->DEBUG) dump("ratio ({$this->ratio})= r({$this->r}) / q({$this->q})");
if ($this->DEBUG) dump("N ({$this->n})= (factor ({$factor}) * vel ({$this->vel})");
if ($this->DEBUG) dump("T ({$this->t}) = N({$this->n}) * QR({$this->q})^0.5 / (reject ({$this->reject}) * 2) ^ 0.75");
if ($this->DEBUG) dump("P ({$this->p}) = N ({$this->n}) * Q({$this->q})^0.5 / (feed ({$this->feed}) * 2)^ 0.75");

我上面的内容是紧密耦合的,理想情况下我想删除该耦合,computationcomputation output分开。我没有看到如何干净地完成这项工作,也没有重复计算。我希望看到所有中间值的输出,而不仅仅是最终结果。

2 个答案:

答案 0 :(得分:1)

没有真正的超级好(我知道 - 如果有请告诉我的!)记录的方式没有用您正在记录的代码封装...

您可以使用get / set方法隐藏每个变量的日志记录。

使用魔术方法获取/设置方法:

您需要修改包含变量的类,其行为如下:

将变量更改为私有

变量必须与get / set方法的名称匹配(例如ratio =&gt; getratio / setratio)

实现get / set / __ get和__set方法

添加了一个记录器方法来为您执行if语句,以使get / set方法尽可能保持干净

class MyClass
{
    private $ratio;

    // Setter method
    // Allows for additional work when setting the value
    // Here we can output the log as we want then set the value
    public function setratio($ratio)
    {
         logger("ratio ({$this->ratio})= r({$this->r}) / q({$this->q})");
         $this->ratio = $ratio;
    }

    // Getter method
    // Allows for additional work when getting the value
    // Here we can just retrieve the value of the variable
    public function getratio()
    {
        return $this->ratio;
    } 

    // Magic Method __set
    // Here we are able to use Variable Function calls to call the appropriate setter
    // This is automatically called when using the syntax $this->ratio = value where ratio is a private property
    public function __set($name, $value) 
    {
        $functionName ='set'.$name;
        return $this->$functionName($value);
    }

    // Magic Method __get
    // Here we are able to use Variable Function calls to call the appropriate getter
    // This is automatically called when using the syntax $this->ratio where ratio is a private property
    public function __get($name) 
    {
        $functionName = 'get'.$name;
        return $this->$functionName();
    }

    // Custom function for logging. Only need to call this and it'll check DEBUG for us
    public function logger($message)
    {
        if ($this->DEBUG) 
            dump($message);
    }
} 

这种方式,当您致电calcSpeed时,您只需

$this->ratio = $this->r / $this->q;
$this->n = ($factor * $this->vel);
$this->t = $this->n * pow($this->r, 0.5) / pow(($this->reject * 2), 0.75);
$this->p = $this->n * pow($this->q, 0.5) / pow(($this->feed * 2), 0.75);

虽然这只适用于所设置的变量,而不仅仅是随机调用转储,但不幸的是它们必须保持原样,但是你可以将它们移动到方法本身中以稍微整理一下循环并使用用于删除ifs的记录器方法。

这将通过以下方式整理循环:

$rows = db_query("select..*");
foreach($rows as row)
{
    $description = $row['model'];

    //dump() prints output on screen
    $this->logger("<h1>Trying {$description}...</h1>");
    $this->calcSpeed();
    $this->checkFlow();
}

并且每个方法都是

function calcSpeed()
{
    $this->logger("Checking Speed . . . ")
    $this->ratio = $this->r / $this->q;
    $this->n = ($factor * $this->vel);
    $this->t = $this->n * pow($this->r, 0.5) / pow(($this->reject * 2), 0.75);
    $this->p = $this->n * pow($this->q, 0.5) / pow(($this->feed * 2), 0.75);
    // Any other code
}

function checkFlow()
{
    $this->logger("Checking Flow . . . ")
    // Rest of code
}

答案 1 :(得分:0)

我有一个通用的思想指南,可能需要花费很多工作才能实现,但可能值得:

将公式视为数据(并将公式的数据视为数据)。

对于PHP,有一个名为symfony/expression-language的库,它允许您评估和解释公式。有了它,就可以编译和解释自定义公式。

因此,我相信可以这样做:

  • 将公式编码到数据库中,作为一个真正的公式来源
  • (可选)使用库将语句编译为PHP代码
  • 通过库解释数据库中的公式,用于计算和记录目的

示例代码

$expressions = //load from database
$language = new \Symfony\Component\ExpressionLanguage();
$data = array(); //storage of intermediate results.
foreach ($expressions as $expression)
{
    /*
     * Evaluate the formula
     */
    $data[$expression->getVariable()] = 
        $language->evaluate($expression->getExpression(), $data);

    /*
     * Add facilities to output the formulas/expressions here:
     * example only, where a and b defined in previously-processed formulas
     */
     print $expression->getVariable() . ' = ' .       //c =
           $expression->getExpression() . ' = ' .     //sqrt(a**2+b**2) =
           data[$expression->getVariable()] . '<br>'; //5<br>
}