Сохранить расчет в коде или базе данных?

Я настраиваю систему, которая будет выполнять различные вычисления на примитивных данных и предоставлять вывод, основанный на вычислении.

Мой главный вопрос – скорее совет, чем руководство.

Использование базы данных 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';} 

и т. д. Затем они вычисляются в php с использованием eval( $calcArray['calc_code']);

4 вычисления никогда не изменятся, хотя в будущем может быть добавлено больше.

Вопрос в том, должен ли я создать этот код в функции PHP, или это нормально, чтобы оставаться в базе данных, как есть? Исходя из того, что можно добавить больше, я склоняюсь к базе данных, так как я могу добавить новые строки для обработки новых типов вычислений, вместо того, чтобы редактировать любой код.

Надеюсь, это все имеет смысл, извинения за длинный вопрос и, вероятно, извращенное форматирование.

Заранее спасибо.

Eval is Evil

Прежде всего: не используйте eval() если нет веской причины. И никогда не бывает веской причины .

в худшем случае eval() делает ваше приложение уязвимым для инъекционных атак, а также очень медленно. Немногие исследования показывают множество причин, почему eval – это большой нет-нет.

Не сохраняйте код расчета в базе данных

Если вы это сделаете, и вы хотите переключиться с PHP на другой язык, у вас все равно будет код PHP в вашей базе данных. Это очень сложно переносить языки. Вы всегда должны стремиться к тому, чтобы максимально использовать часть вашего приложения как можно более независимое.

В этом случае вы должны привязать язык, который вы используете, к базе данных. Это плохая практика.

Кроме того, единственные возможности запуска ваших вычислений из базы данных состоят в том, чтобы оценить их (что плохо, см. Выше) или разобрать строку со строковыми операциями или регулярным выражением, что приводит к ненужным усилиям.

Это все о стратегии

Чтобы решить вашу проблему, вы должны выполнить код, зависящий от того, какой расчет вам нужен. Это можно сделать либо с помощью операторов switch-case или if-statements. Но это тоже не очень изящное решение. Представьте, что вам нужно будет выполнить другие операции перед вычислением в будущем или расширить функциональность. Вам нужно будет обновить все ваши дела или if-statements.

Существует красивый дизайн-шаблон, который называется 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(); } } 

Наиболее важная часть здесь – конструктор. Посмотрите, как мы печатаем, – подскажите наш интерфейс здесь. Делая это, мы гарантируем, что может быть введен только объект ( Injection Dependency ), класс которого реализует интерфейс . Здесь нам не нужно требовать конкретного класса. Это очень важный момент.

Также есть метод расчета. Это просто оболочка для нашей стратегии, чтобы выполнить ее метод расчета.

Обертывание

Итак, теперь нам просто нужно создать объект нашего класса Calculator и передать объект одного из наших классов стратегии (который содержит код для арифметических операций).

 <?php //The corresponding string is stored in your DB $calculatable = 'Division'; $calc = new Calculator( new $calculatable(15, 100) ); echo $calc->calculate(); 

Попробуйте заменить строку, хранящуюся в $calculatable на Percentage и вы увидите, что будет выполняться операция вычисления процента.

Вывод

Шаблон стратегии позволил вам создать чистый интерфейс для работы с динамическими задачами, которые выполняются только во время выполнения. Ни ваша база данных не должна знать, как мы вычисляем вещи, ни ваш фактический калькулятор. Единственное, что нам нужно сделать, это сделать код против интерфейса, который предоставляет метод, позволяющий нам вычислять вещи.

Если бы я был вами, я не буду вносить расчет php в базу данных. Зачем? Скажем, вы решили написать свою систему на другом языке, вам нужно будет проанализировать эти php-коды в db и преобразовать их в новые особенности языка (это худший сценарий). Если бы я был вами, я преобразую это в службу и разделить на части. Вы можете поместить каждый вызов в очередь заданий, после завершения задания вы можете сохранить результаты в db. Вы можете использовать эту услугу для нескольких типов клиентов.

Вы можете создавать функции для каждого вычисления, чтобы легко сменить алгоритм вычислений. Кроме того, вы можете добавить новый расчет как функцию.

Если я понимаю ваш вопрос, у вас есть база данных, содержащая данные домена, и множество вычислений, которые вы выполняете по этим данным. В настоящее время вы храните эти вычисления как строки в базе данных и выполняете эти вычисления, используя eval() .

Есть несколько причин для этого, я могу себе представить – легко распределить вычисления между разными экземплярами вычислений (чтобы вы могли запускать несколько параллельных вычислений или создавать новые расчетные клиенты (например, веб-клиент, клиент командной строки, мобильное приложение) , А также упрощает управление расчетами – все они живут в одном месте.

Однако есть некоторые очевидные недостатки:

  • вы не можете легко проверить новый расчет. Вы должны вставить его в базу данных, а затем посмотреть, что-нибудь сломается.
  • злоумышленник, который может вставлять строки в таблицу расчета, может заставить вас выполнить произвольный код.
  • логически, данные домена и логика расчета – это не одно и то же.

Итак, у вас есть множество альтернатив. В подобных сценариях я часто создавал папку в своей структуре приложения с вычислениями и использовал потоки файлов для динамического загрузки кода вычисления. Используя систему управления исходным кодом с автоматизированными развертываниями, вы можете развернуть это на любое количество экземпляров вычислений.

Для более сложных сценариев я создал небольшой язык, специфичный для домена . Это вполне возможно в PHP . В вашем случае это позволит вам удалить много логики ведения домашнего хозяйства ( $primBVal != 0 ) и сосредоточиться на домене. Это нетривиально, но если у вас сотни вычислений, это может стоить того.

Я запускаю сайт исследования рынка, где действительно нужно много вычислений, в основном показатели производительности. мой опыт и моя фактическая работа говорят мне, что вы должны использовать скрипты php вместо строк базы данных, добавленные «на лету». Это потому, что у вас есть рабочий процесс, которым лучше управлять, перемещая и удаляя фрагменты кода. База данных должна хорошо работать как рабочий процесс. менеджером или процессами.