Я ищу конкретный совет рефакторинга.
Во-первых, у меня был скрипт только с вычислениями и без вывода. Я хотел закодировать вывод вычислений, чтобы на экране были видны как формулы, так и их фактические значения.
И поэтому я реализовал 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");
То, что я имею выше, тесно связано, и в идеале я хотел бы удалить это соединение и иметь computation
быть отдельным от computation output
, Я не вижу, как сделать это чисто и без дублирования вычислений. Я хочу видеть вывод всех промежуточных значений, а не только конечный результат.
На самом деле не существует супер-приятного (который я знаю — если есть, пожалуйста, скажите мне!) Способа регистрации, который не инкапсулирован с кодом, который вы регистрируете, однако …
Вы можете скрыть ведение журнала для каждой переменной, используя методологию get / set.
Метод Get / Set с помощью магических методов:
Вам нужно изменить класс, содержащий переменные, чтобы они действовали следующим образом:
Изменить переменную на частную
Переменная должна соответствовать названию методов get / set (например, ratio => getratio / setratio)
Реализуйте методы get / set / __ get и __set
Добавлен метод logger, чтобы сделать оператор 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);
Хотя это будет работать только для устанавливаемых переменных, а не только для случайных вызовов дампа, поэтому, к сожалению, им придется оставаться там, где они есть, однако вы можете переместить их в сами методы, чтобы немного привести в порядок цикл, а также использовать метод logger. удалить если.
Это приведёт в порядок цикл следующим образом:
$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
}
У меня есть общие рекомендации, которые могут потребовать много времени для реализации, но, возможно, они того стоят:
обрабатывать формулы как данные (и обрабатывать данные для формул также как данные).
Для PHP есть библиотека под названием symfony/expression-language
, что позволяет оценивать и интерпретировать формулы. С его помощью можно составлять и интерпретировать пользовательские формулы.
Таким образом, я считаю, что можно сделать что-то вроде этого:
Образец кода
$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>
}