Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Berechnung in Code oder Datenbank speichern?

Eval ist böse

Zunächst einmal:Verwenden Sie nicht eval() es sei denn, es gibt einen triftigen grund. Und es gibt nie einen guten Grund .

im schlimmsten Fall eval() macht Ihre Anwendung anfällig für Injektionsangriffe und ist außerdem sehr langsam. Ein wenig Recherche zeigt viele Gründe, warum eval ein großes No-Go ist.

Speichern Sie Ihren Berechnungscode nicht in der Datenbank

Wenn Sie dies tun und von PHP zu einer anderen Sprache wechseln möchten, haben Sie immer noch PHP-Code in Ihrer Datenbank. Es macht es wirklich schwierig, Sprachen zu migrieren. Sie sollten immer danach streben, so viele Teile Ihrer Bewerbung so unabhängig wie möglich zu gestalten.

In diesem Fall würden Sie die von Ihnen verwendete Sprache eng an die Datenbank koppeln. Das ist eine schlechte Vorgehensweise.

Außerdem wäre die einzige Möglichkeit, Ihre Berechnungen aus der Datenbank auszuführen, sie auszuwerten (was schlecht ist, siehe oben) oder den String mit Stringoperationen oder Regex zu zerlegen, was unnötigen Aufwand verursacht.

Es dreht sich alles um Strategie

Um Ihr Problem zu lösen, müssen Sie Code ausführen, der davon abhängt, welche Berechnung Sie benötigen. Dies kann entweder mit switch-case-Anweisungen oder mit if-Anweisungen erfolgen. Das ist aber auch keine sehr elegante Lösung. Stellen Sie sich vor, Sie müssten andere Operationen ausführen, bevor Sie in Zukunft berechnen, oder die Funktionalität erweitern. Sie müssten alle Ihre Fälle oder if-Anweisungen aktualisieren.

Es gibt ein nettes Design-Muster namens Strategy Pattern . Das Strategiemuster löst Probleme, wenn ein Anwendungsfall anders gehandhabt werden kann, was wahrscheinlich das ist, was Sie wollen.

Sie wollen etwas berechnen (Use-Case) und dafür gibt es verschiedene Berechnungsarten (verschiedene Strategien)

Wie es funktioniert

Um das Strategiemuster zu implementieren, benötigen Sie im Wesentlichen drei Dinge.

  • Eine Klasse, in der Sie Ihre Strategien einbringen. Es ist im Grunde ein Wrapper für Ihre Strategieaufgaben.
  • Eine Schnittstelle, die von Ihren Strategien implementiert wird
  • Ihre Strategien

Ihre Benutzeroberfläche könnte so aussehen:

<?php
interface CalculatableInterface {
    
    public function calculate();

}

Die Schnittstelle stellt sicher, dass alle Ihre Strategien eine Methode bieten, um die Berechnung tatsächlich auszuführen. Nichts besonderes.

Als nächstes möchten Sie vielleicht eine Basisklasse haben, die Ihre Berechnungsoperatoren als Konstruktorargumente nimmt und sie in Eigenschaften speichert.

<?php
abstract class Calculatable {

    protected $valueA;
    protected $valueB;

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

}

Jetzt wird es ernst. Wir setzen unsere Strategien um.

<?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';
    }

}

Natürlich könnte man das ein wenig aufräumen, aber worauf ich hier hinweisen möchte, ist die Klassendeklaration.

Wir erweitern unsere Calculatable Klasse, damit wir die Rechenoperationen per Konstruktor übergeben können und wir implementieren das CalculatableInterface was unserer Klasse sagt:"Hey! Sie müssen eine Berechnungsmethode angeben, es ist mir egal, ob Sie wollen oder nicht.

Wir werden später sehen, warum dies ein integraler Bestandteil des Musters ist.

Wir haben also zwei konkrete Klassen, die den eigentlichen Code für die eigentliche arithmetische Operation enthalten. Wenn Sie es jemals brauchen würden, können Sie es einfach ändern, wie Sie sehen. Um weitere Operationen hinzuzufügen, fügen Sie einfach eine weitere Klasse hinzu.

Jetzt werden wir eine Klasse erstellen, in die unsere Strategien eingefügt werden können. Später werden Sie ein Objekt dieser Klasse instanziieren und damit arbeiten.

So sieht es aus:

<?php 
class Calculator {

    protected $calculatable;

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

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

}

Der wichtigste Teil hier ist der Konstruktor. Sehen Sie hier, wie wir unsere Benutzeroberfläche mit Hinweisen versehen. Dadurch stellen wir sicher, dass nur ein Objekt injiziert werden kann (Dependency Injection ). ), dessen Klasse die Schnittstelle implementiert . Wir brauchen hier keine konkrete Klasse zu fordern. Das ist hier der entscheidende Punkt.

Da ist auch eine Berechnungsmethode drin. Es ist nur ein Wrapper für unsere Strategie, um ihre Berechnungsmethode auszuführen.

Einpacken

Jetzt müssen wir also nur noch ein Objekt unseres Calculator erstellen Klasse und übergeben Sie ein Objekt einer unserer Strategieklassen (die den Code für die arithmetischen Operationen enthalten).

<?php
//The corresponding string is stored in your DB
$calculatable = 'Division';

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

Versuchen Sie, die in $calculatable gespeicherte Zeichenfolge zu ersetzen zu Percentage und Sie sehen, dass die Operation zur Berechnung des Prozentsatzes ausgeführt wird.

Schlussfolgerung

Mit dem Strategiemuster haben Sie eine saubere Oberfläche für die Arbeit mit dynamischen Aufgaben geschaffen, die erst zur Laufzeit konkretisiert werden. Weder Ihre Datenbank muss wissen, wie wir Dinge berechnen, noch Ihr eigentlicher Taschenrechner. Das einzige, was wir sicherstellen müssen, ist, gegen eine Schnittstelle zu codieren das stellt eine Methode bereit, mit der wir Dinge berechnen können.