sql >> Database >  >> RDS >> Mysql

Berekening opslaan in code of database?

Eval is het kwaad

Allereerst:gebruik geen eval() tenzij er een goede reden voor is. En er is nooit een goede reden .

in het ergste geval eval() maakt uw applicatie kwetsbaar voor injectieaanvallen en is ook erg traag. Een beetje onderzoek onthult tal van redenen waarom eval een grote no-no is.

Sla uw berekeningscode niet op in de database

Als u dit doet en u wilt overstappen van PHP naar een andere taal, dan heeft u nog steeds PHP-code in uw database. Het maakt het echt moeilijk om talen te migreren. U moet er altijd naar streven om zoveel mogelijk onderdelen van uw aanvraag zo onafhankelijk mogelijk te maken.

In dit geval koppelt u de taal die u gebruikt aan de database. Dat is een slechte gewoonte.

De enige mogelijkheden om uw berekeningen vanuit de database uit te voeren, zijn ze te evalueren (wat slecht is, zie hierboven) of de string te demonteren met stringbewerkingen of regex, wat onnodige inspanning veroorzaakt.

Het draait allemaal om Strategie

Om uw probleem op te lossen, moet u code uitvoeren, afhankelijk van welke berekening u nodig heeft. Dat kan met switch-case-statements of if-statements. Maar ook dat is geen erg elegante oplossing. Stelt u zich eens voor dat u andere bewerkingen moet uitvoeren voordat u in de toekomst kunt rekenen, of dat u de functionaliteit moet uitbreiden. U zou al uw cases of if-statements moeten bijwerken.

Er is een mooi ontwerppatroon genaamd Strategy Pattern . Het strategiepatroon lost problemen op wanneer een use-case anders kan worden behandeld, wat waarschijnlijk is wat u wilt.

Je wilt iets berekenen (use-case) en er zijn verschillende berekeningstypes voor (verschillende strategieën)

Hoe het werkt

Om het Strategiepatroon te implementeren heb je in principe drie dingen nodig.

  • Een les waarin je je strategieën injecteert. Het is eigenlijk een wrapper voor je strategietaken.
  • Een interface die door uw strategieën wordt geïmplementeerd
  • Uw strategieën

Uw interface zou er als volgt uit kunnen zien:

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

}

De interface zorgt ervoor dat al uw strategieën een methode bieden om de berekening daadwerkelijk uit te voeren. Niets bijzonders.

Vervolgens wil je misschien een basisklasse hebben die je berekeningsoperatoren als constructorargumenten neemt en ze opslaat in eigenschappen.

<?php
abstract class Calculatable {

    protected $valueA;
    protected $valueB;

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

}

Nu wordt het serieus. We voeren onze strategieën uit.

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

}

Je zou deze natuurlijk een beetje kunnen opschonen, maar waar ik hier op wil wijzen is de klasseverklaring.

We breiden onze Calculatable . uit class zodat we de rekenkundige bewerkingen kunnen doorgeven via de constructor en we implementeren de CalculatableInterface die onze klas vertelt:"Hé! Je moet een berekeningsmethode opgeven, het kan me niet schelen of je wilt of niet.

We zullen later zien waarom dit een integraal onderdeel van het patroon is.

We hebben dus twee concrete klassen die de eigenlijke code voor de eigenlijke rekenkundige bewerking bevatten. Als je het ooit nodig hebt, kun je het gemakkelijk veranderen, zoals je ziet. Om meer bewerkingen toe te voegen, voeg je gewoon een andere klas toe.

Nu gaan we een klasse maken waarin onze strategieën kunnen worden geïnjecteerd. Later zal je een object van deze klasse instantiëren en ermee werken.

Zo ziet het eruit:

<?php 
class Calculator {

    protected $calculatable;

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

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

}

Het belangrijkste onderdeel hier is de constructor. Bekijk hier hoe we onze interface typen. Door dat te doen zorgen we ervoor dat alleen een object kan worden geïnjecteerd (Dependency Injection ) wiens klasse de interface implementeert . We hoeven hier geen concrete les te eisen. Dat is het cruciale punt hier.

Er zit ook een berekeningsmethode in. Het is slechts een omslag voor onze strategie om de berekeningsmethode uit te voeren.

Het afronden

Dus nu hoeven we alleen maar een object te maken van onze Calculator class en geef een object door van een van onze strategieklassen (die de code voor de rekenkundige bewerkingen bevatten).

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

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

Probeer de string te vervangen die is opgeslagen in $calculatable tot Percentage en je ziet dat de bewerking voor het berekenen van het percentage wordt uitgevoerd.

Conclusie

Dankzij het strategiepatroon kon je een schone interface creëren voor het werken met dynamische taken die alleen tijdens runtime concreet worden gemaakt. Noch uw database hoeft te weten hoe wij dingen berekenen, noch uw eigenlijke rekenmachine. Het enige dat we moeten doen, is coderen tegen een interface dat biedt een methode om ons dingen te laten berekenen.



  1. rij naar kolom conversie in mysql

  2. Een rapport groeperen op meerdere velden in Access 2016

  3. Hiërarchische gegevens in MySql

  4. mysql:BRON fout 2?