sql >> Database teknologi >  >> RDS >> Mysql

Gem beregning i kode eller database?

Eval er ond

Først og fremmest:Brug ikke eval() medmindre der er en god grund. Og der er aldrig en god grund .

i værste fald eval() gør din applikation sårbar over for injektionsangreb, og den er også meget langsom. En smule forskning afslører masser af grunde til, at eval er et stort nej-nej.

Gem ikke din beregningskode i databasen

Hvis du gør det, og du gerne vil skifte fra PHP til et andet sprog, vil du stadig have PHP-kode i din database. Det gør det virkelig svært at migrere sprog. Du bør altid stræbe efter at gøre så mange dele af din ansøgning så uafhængige som muligt.

I dette tilfælde vil du tætkoble det sprog, du bruger, til databasen. Det er en dårlig praksis.

De eneste muligheder for at køre dine beregninger fra databasen ville også være at evaluere dem (hvilket er dårligt, se ovenfor) eller at adskille strengen med strengoperationer eller regex, hvilket forårsager unødvendig indsats.

Det handler om strategi

For at løse dit problem skal du udføre kode afhængig af hvilken beregning du skal bruge. Det kunne enten gøres med skifte-tilfælde-udsagn eller hvis-udsagn. Men det er heller ikke en særlig elegant løsning. Forestil dig, at du skal udføre andre operationer, før du beregner i fremtiden, eller udvide funktionaliteten. Du skal opdatere alle dine sager eller hvis-udsagn.

Der er et flot design-mønster, som hedder Strategy Pattern . Strategimønsteret løser problemer, når en use-case kan håndteres forskelligt, hvilket sandsynligvis er det, du ønsker.

Du vil beregne noget (use-case), og der er forskellige beregningstyper for det (forskellige strategier)

Sådan virker det

For at implementere strategimønsteret har du grundlæggende brug for tre ting.

  • En klasse, hvor du injicerer dine strategier. Det er dybest set en indpakning for dine strategiopgaver.
  • En grænseflade, som vil blive implementeret af dine strategier
  • Dine strategier

Din grænseflade kunne se sådan ud:

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

}

Grænsefladen vil sørge for, at alle dine strategier giver en metode til rent faktisk at køre beregningen. Ikke noget særligt.

Dernæst vil du måske have en basisklasse, der tager dine beregningsoperatorer som konstruktørargumenter og gemmer dem i egenskaber.

<?php
abstract class Calculatable {

    protected $valueA;
    protected $valueB;

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

}

Nu bliver det alvor. Vi implementerer vores strategier.

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

}

Selvfølgelig kunne du rydde lidt op i denne, men det, jeg vil påpege her, er klasseerklæringen.

Vi udvider vores Calculatable klasse, så vi kan videregive de aritmetiske operationer via konstruktøren, og vi implementerer CalculatableInterface som fortæller vores klasse:"Hej! Du skal angive en beregningsmetode, jeg er ligeglad med, om du vil eller ej.

Vi vil senere se, hvorfor dette er en integreret del af mønsteret.

Så vi har to konkrete klasser, der indeholder den faktiske kode for den faktiske regneoperation. Hvis du nogensinde får brug for det, kan du nemt ændre det, som du ser. For at tilføje flere handlinger skal du blot tilføje en anden klasse.

Nu vil vi lave en klasse, hvor vores strategier kan injiceres. Senere vil du instansiere et objekt fra denne klasse og arbejde med det.

Sådan ser det ud:

<?php 
class Calculator {

    protected $calculatable;

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

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

}

Den vigtigste del her er konstruktøren. Se, hvordan vi indtaster vores grænseflade her. Ved at gøre det sikrer vi, at kun et objekt kan injiceres (Dependency Injection ), hvis klasse implementerer grænsefladen . Vi behøver ikke kræve en konkret klasse her. Det er det afgørende punkt her.

Der er også en beregningsmetode derinde. Det er blot en indpakning for vores strategi at udføre dens beregningsmetode.

Afslutter det

Så nu mangler vi bare at oprette et objekt af vores Calculator klasse og videregive et objekt fra en af ​​vores strategiklasser (som indeholder koden til de aritmetiske operationer).

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

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

Prøv at erstatte strengen, der er gemt i $calculatable til Percentage og du ser, at operationen til beregning af procentdelen vil blive udført.

Konklusion

Strategimønsteret gav dig mulighed for at skabe en ren grænseflade til at arbejde med dynamiske opgaver, der kun bliver konkretiseret under kørsel. Hverken din database behøver at vide, hvordan vi beregner ting, eller din faktiske lommeregner gør det. Det eneste, vi skal sørge for, er at kode mod en grænseflade der giver en metode til at lade os beregne ting.



  1. Sådan vælges og sorteres efter kolonner, der ikke er i Groupy By SQL-sætning - Oracle

  2. Er der nogen SQL-validatorer, der kan kontrollere syntaks mod flere databaseservere?

  3. Hvordan gemmer man adgangskoder sikkert i databasen?

  4. MySQL - BETWEEN vil ikke vælge korrekte resultater