Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Salvar cálculo em código ou banco de dados?

Eval é mau


Primeiro de tudo:não use eval() a menos que haja uma boa razão. E nunca há uma boa razão .

no pior caso eval() torna seu aplicativo vulnerável a ataques de injeção e também é muito lento. Um pouco de pesquisa revela muitas razões pelas quais o eval é um grande não-não.

Não salve seu código de cálculo no banco de dados


Se você fizer isso e quiser mudar de PHP para outra linguagem, você ainda terá código PHP em seu banco de dados. Isso torna muito difícil migrar idiomas. Você deve sempre se esforçar para tornar o maior número possível de partes de seu aplicativo o mais independente possível.

Nesse caso, você associaria o idioma que usa ao banco de dados. Isso é uma má prática.

Além disso, as únicas possibilidades de executar seus cálculos a partir do banco de dados seriam avaliá-los (o que é ruim, veja acima) ou desmontar a string com operações de string ou regex, o que causa esforço desnecessário.

É tudo sobre Estratégia


Para resolver seu problema, você deve executar um código dependente de qual cálculo você precisa. Isso pode ser feito com instruções switch-case ou instruções if. Mas isso também não é uma solução muito elegante. Imagine que você precisaria executar outras operações antes de calcular no futuro ou estender a funcionalidade. Você precisaria atualizar todos os seus casos ou declarações if.

Existe um bom padrão de design chamado Padrão de estratégia . O padrão de estratégia resolve problemas quando um caso de uso pode ser tratado de maneira diferente, o que provavelmente é o que você deseja.

Você deseja calcular algo (caso de uso) e existem diferentes tipos de cálculo para isso (diferentes estratégias)

Como funciona


Para implementar o padrão Strategy você precisa basicamente de três coisas.
  • Uma aula em que você injeta suas estratégias. É basicamente um wrapper para suas tarefas de estratégia.
  • Uma interface que será implementada por suas estratégias
  • Suas estratégias

Sua interface pode ficar assim:
<?php
interface CalculatableInterface {
    
    public function calculate();

}

A interface garantirá que todas as suas estratégias forneçam um método para realmente executar o cálculo. Nada especial.

Em seguida, você pode querer ter uma classe base que leve seus operadores de cálculo como argumentos do construtor e os armazene em propriedades.
<?php
abstract class Calculatable {

    protected $valueA;
    protected $valueB;

    public function __construct($valueA, $valueB)
    {
        $this->valueA = $valueA;
        $this->valueB = $valueB;
    }

}

Agora está ficando sério. Estamos implementando nossas estratégias.
<?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';
    }

}

Claro que você poderia limpar um pouco isso, mas o que eu quero destacar aqui é a declaração de classe.

Estamos estendendo nosso Calculatable class para que possamos passar as operações aritméticas via construtor e estamos implementando a CalculatableInterface que diz à nossa classe:"Ei! Você deve fornecer um método de cálculo, não importa se você quer ou não.

Veremos mais tarde por que isso é parte integrante do padrão.

Portanto, temos duas classes concretas que contêm o código real para a operação aritmética real. Se você precisar, você pode alterá-lo facilmente como você vê. Para adicionar mais operações, basta adicionar outra classe.

Agora vamos criar uma classe onde nossas estratégias podem ser injetadas. Mais tarde você instanciará um objeto desta classe e trabalhará com ele.

Aqui está como se parece:
<?php 
class Calculator {

    protected $calculatable;

    public function __construct( CalculatableInterface $calculatable )
    {
        $this->calculatable = $calculatable;
    }

    public function calculate()
    {
        return $this->calculatable->calculate();
    }

}

A parte mais importante aqui é o construtor. Veja como digitamos nossa interface aqui. Ao fazer isso, garantimos que apenas um objeto possa ser injetado (Injeção de dependência ) cuja classe implementa a interface . Não precisamos exigir uma classe concreta aqui. Esse é o ponto crucial aqui.

Também há um método de cálculo lá. É apenas um wrapper para nossa estratégia executar seu método de cálculo.

Encerrando


Então agora só precisamos criar um objeto da nossa Calculator class e passar um objeto de uma de nossas classes de estratégia (que contém o código para as operações aritméticas).
<?php
//The corresponding string is stored in your DB
$calculatable = 'Division';

$calc = new Calculator( new $calculatable(15, 100) );
echo $calc->calculate();

Tente substituir a string armazenada em $calculatable para Percentage e você vê que a operação de cálculo do percentual será executada.

Conclusão


O padrão de estratégia permitiu que você criasse uma interface limpa para trabalhar com tarefas dinâmicas que só são concretizadas durante o tempo de execução. Nem seu banco de dados precisa saber como calculamos as coisas, nem sua calculadora real. A única coisa que precisamos ter certeza é codificar em uma interface que fornece um método para nos permitir calcular as coisas.