Eval è il male
Prima di tutto:non usare eval()
a meno che non ci sia una buona ragione. E non c'è mai una buona ragione .
nel peggiore dei casi eval()
rende la tua applicazione vulnerabile agli attacchi di injection ed è anche molto lenta. Un po' di ricerca rivela molte ragioni per cui eval è un grande no.
Non salvare il tuo codice di calcolo nel database
Se lo fai e desideri passare da PHP a un'altra lingua, avresti ancora il codice PHP nel tuo database. Rende davvero difficile la migrazione delle lingue. Dovresti sempre sforzarti di rendere il maggior numero possibile di parti della tua applicazione indipendenti.
In questo caso accoppieresti la lingua che usi al database. È una cattiva pratica.
Inoltre, l'unica possibilità per eseguire i tuoi calcoli dal database sarebbe valutarli (il che non è valido, vedi sopra) o disassemblare la stringa con operazioni di stringa o regex che causano sforzi inutili.
Si tratta di Strategia
Per risolvere il tuo problema devi eseguire il codice in base al calcolo di cui hai bisogno. Ciò potrebbe essere fatto con dichiarazioni switch-case o if-dichiarazioni. Ma anche questa non è una soluzione molto elegante. Immagina di dover eseguire altre operazioni prima di calcolare in futuro o di estendere la funzionalità. Dovresti aggiornare tutti i casi o le dichiarazioni if.
C'è un bel design pattern che si chiama Strategy Pattern . Il modello di strategia risolve i problemi quando un caso d'uso può essere gestito in modo diverso, il che probabilmente è quello che vuoi.
Vuoi calcolare qualcosa (caso d'uso) e ci sono diversi tipi di calcolo per esso (diverse strategie)
Come funziona
Per implementare il modello della Strategia hai fondamentalmente bisogno di tre cose.
- Una lezione in cui inietti le tue strategie. È fondamentalmente un wrapper per le tue attività strategiche.
- Un'interfaccia che sarà implementata dalle tue strategie
- Le tue strategie
La tua interfaccia potrebbe assomigliare a questa:
<?php
interface CalculatableInterface {
public function calculate();
}
L'interfaccia si assicurerà che tutte le tue strategie forniscano un metodo per eseguire effettivamente il calcolo. Niente di speciale.
Successivamente potresti voler avere una classe base che prenda i tuoi operatori di calcolo come argomenti del costruttore e li memorizzi in proprietà.
<?php
abstract class Calculatable {
protected $valueA;
protected $valueB;
public function __construct($valueA, $valueB)
{
$this->valueA = $valueA;
$this->valueB = $valueB;
}
}
Ora si fa sul serio. Stiamo implementando le nostre strategie.
<?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';
}
}
Ovviamente potresti ripulire un po' questo, ma quello che voglio sottolineare qui è la dichiarazione di classe.
Stiamo estendendo il nostro Calculatable
classe in modo da poter passare le operazioni aritmetiche tramite il costruttore e stiamo implementando il CalculatableInterface
che dice alla nostra classe:"Ehi! Devi fornire un metodo di calcolo, non mi interessa se lo vuoi o no.
Vedremo più avanti perché questo è parte integrante del modello.
Quindi abbiamo due classi concrete che contengono il codice effettivo per l'operazione aritmetica effettiva. Se mai ne avessi bisogno, puoi cambiarlo facilmente come vedi. Per aggiungere più operazioni, aggiungi un'altra classe.
Ora creeremo una classe in cui le nostre strategie possono essere iniettate. Successivamente creerai un'istanza di un oggetto di questa classe e lavorerai con esso.
Ecco come appare:
<?php
class Calculator {
protected $calculatable;
public function __construct( CalculatableInterface $calculatable )
{
$this->calculatable = $calculatable;
}
public function calculate()
{
return $this->calculatable->calculate();
}
}
La parte più importante qui è il costruttore. Guarda come digitiamo la nostra interfaccia qui. In questo modo ci assicuriamo che solo un oggetto possa essere iniettato (Iniezione di dipendenza ) la cui classe implementa l'interfaccia . Non abbiamo bisogno di chiedere una classe concreta qui. Questo è il punto cruciale qui.
Inoltre c'è un metodo di calcolo lì dentro. È solo un involucro per la nostra strategia per eseguire il metodo di calcolo.
Concludendo
Quindi ora dobbiamo solo creare un oggetto della nostra Calculator
class e passare un oggetto di una delle nostre classi di strategia (che contiene il codice per le operazioni aritmetiche).
<?php
//The corresponding string is stored in your DB
$calculatable = 'Division';
$calc = new Calculator( new $calculatable(15, 100) );
echo $calc->calculate();
Prova a sostituire la stringa memorizzata in $calculatable
a Percentage
e vedi che verrà eseguita l'operazione di calcolo della percentuale.
Conclusione
Il modello di strategia ha consentito di creare un'interfaccia pulita per lavorare con attività dinamiche che vengono rese concrete solo durante il runtime. Né il tuo database ha bisogno di sapere come calcoliamo le cose, né la tua calcolatrice reale. L'unica cosa di cui dobbiamo assicurarci è codificare su un'interfaccia che fornisce un metodo per farci calcolare le cose.