Avatar billede chrisrj Forsker
10. oktober 2018 - 14:46 Der er 12 kommentarer og
2 løsninger

nulstille klasse objekt i klassen?

Hejsa

Jeg stødte på et "sjovt"/underligt problem.

Jeg har en klasse, user, som jeg bruger på følgende måde:

først oprettes objektet:

$newUser = new User;

så hentes data fra databasen (pt. findes brugeren ikke):

$newUser = $newUser->getUser(1);

Så udskrives bruger id'et (og korrekt er der intet data):

echo "UID: ".$newUser->getUID()."<br>";

så opdaterer jeg objektet:
echo "UpdateUser: ".$newUser->UpdateUser(array('intNewsletter' => '25', 'intLangID' => '5', 'strCountryCode' => '465', 'strPicture' => 'uggh5', 'strPhoneNumber' => '132465785', 'intUserType' => '9', 'boolActive' => '5', 'strFullName' => 'Jørgen55', 'strUserName' => 'JørgenII55', 'strEmail' => 'Jørgen@jørgen.dk55'))."<br>";

og så sletter jeg det:

echo $newUser->DeleteUser();

her skulle man så mene at objektet burde være tomt, men nej! Ved udskrift har alle props værdier:
echo "UID: ".$newUser->getUID()."<br>";

I min DeleteUser funktion har jeg følgende:
$instance = new self();
               
$instance->setUID(null);


setUID har ingen begrænsninger på input:

    protected function setUID($newval)
    {
        $this->intUID = $newval;
    }

Så hvorfor pokker har objektet stadig det slettede indhold??
Avatar billede arne_v Ekspert
10. oktober 2018 - 15:05 #1
Designet virker noget usaedvaneligt.

Saa vidt jeg kan se, saa har din User klasse to helt forskellige functionaer:
1) holder af data for bruger
2) manipulation af bruger (get, update, delete)

Hvis du splitter de to i to forskellige funktioner, saa tror jeg at dit problem ogsaa forsvinder helt automatisk.
Avatar billede Slater Ekspert
10. oktober 2018 - 15:06 #2
Hvad er $instance?

Der mangler jo en del kode, men umiddelbart ser det ud som om du opretter et nyt objekt (new self) og så sætter dets værdi til ingenting, og derefter ignorerer du bare det nye objekt, så det bliver slettet når funktionen afslutter.
Avatar billede chrisrj Forsker
10. oktober 2018 - 15:12 #3
@arne Hehe, er det et halvvejs kompliment? ;p Nå, spøg til side...
Jeg har helt klar over, at man normalt ikke gør sådan. Men i mit tilfælde er fint nok.

@slater:
øhm...jah, altså...nu må jeg jo nok krybe lidt til korset og tilstå at OO i php er relativt nyt for mig, så jeg har BARE brugt koden fra nettet.
Der blev sagt at det var _måden_ at rydde data fra et objekt....men jeg skal så bare returnere objektet og så er alt fjong?? :D
Avatar billede Slater Ekspert
10. oktober 2018 - 15:28 #4
Umiddelbart ville jeg mene du nærmere skulle sætte $this->setUID(null);
Men det kommer meget an på resten af koden, og hvad dette User objekt skal gøre. Jeg går ud fra det er en model til en database på en eller anden måde?

Jeg forstår umiddelbart slet ikke pointen med at køre en slet-metode på objektet, i stedet for bare at lade være med at anvende det, eller bare køre unset($newUser); hvis det skal helt væk. Hvorfor benytte samme objekt og nulstille værdierne? Er det fordi det også skal slettes fra databasen?

Jeg tror vi har brug for at vide mere.
Avatar billede arne_v Ekspert
10. oktober 2018 - 15:30 #5
Hvis du har baade en User og en UserManager klasse, saa er ddet nemt at slette. UserManager har en delete metode til at slette bruger i databasen. Og User instansen i memory forsvinder bare naar du ikke laegere har en referance til den.
Avatar billede chrisrj Forsker
10. oktober 2018 - 15:42 #6
Ok, jeg laver lille uddybning her:

Jeg har min user klasse og i den klasse kan man oprette/rette/slette mm - OGSÅ rækken i databasen.

Grunden til at jeg ikke har delt det op, er at jeg ikke umiddelbart ser et formål med det. Jeg VED at jeg har aldrig skal skifte databasetype (men muligvis navnet/sti til den - så det ligger for sig) og tabelnavnene er lagt ud i en config fil.

Jeg har ikke behov for et super optimeret eller skaleringsrettet design.

Jeg ville gerne have det sådan, at ønsker jeg at slette useren, jamen så gøres det i klassen, så jeg ikke skal rode med det i den konkrete implementering. Men det kan man måske ikke sådan "bare" (dvs. uden at gå arne-vejen)?
Avatar billede chrisrj Forsker
10. oktober 2018 - 15:45 #7
Hele min delete funktion:

    public function DeleteUser() {
        $objLog = new Log;
        if ($this->intUID != "") {
           
            // get a connection to the db
            include('db_conn.php');
           
            // do the db thing
            if (!($update_stmt = $mysqli->prepare("DELETE FROM ".UsersTable." WHERE UID=?"))) {
                $objLog->LogIt(array('LogType' => '3', 'LogText' => 'DeleteUser: prepare fail. ('.$update_stmt->errno.') '.$update_stmt->error));
                return false;
            }
           
            //echo "intUID: ".$UID."<br>";
           
            if (!($update_stmt->bind_param('i', $this->intUID))) {
                $objLog->LogIt(array('LogType' => '3', 'LogText' => 'DeleteUser: bind fail. ('.$update_stmt->errno.') '.$update_stmt->error));
                return false;
            }
           
            // Execute the prepared query.
            if (!($update_stmt->execute())) {
                $objLog->LogIt(array('LogType' => '3', 'LogText' => 'DeleteUser: execute fail. ('.$update_stmt->errno.') '.$update_stmt->error));
                return false;
            } else {
                $status = "DeleteUser: Success";
               
                $objLog->LogIt(array('LogType' => '1', 'LogText' => $status));
               
                // out with old, in with the new
                //$this = new self();
               
                $this->setUID(null);
                $this->setFullName(null);
                $this->setPhoneNumber(null);
                $this->setEmail(null);
                $this->setCountryCode(null);
                $this->setPicture(null);
                $this->setNewsletter(null);
                $this->setUserName(null);
                $this->setActive(null);
                $this->setLangID(null);
                $this->setUserType(null);
                $this->setCreatedTime(null);
                $this->setUpdatedTime(null);
               
                return true;
            }
        } else {
            echo $objLog->LogIt(array('LogType' => '1', 'LogText' => 'DeleteUser: no user'));
            return false;
        }
    }

Den virker som den skal, men det ville være rart hvis jeg ikke behøvede at nulstille hvert enkelt variabel, OG ej heller lave noget "fikumdik" i implementeringen. :)
Avatar billede Slater Ekspert
10. oktober 2018 - 15:52 #8
Okay, så du sætter allerede alle værdierne til null i DeleteUser. Det er jo helt fint og burde gøre hvad du vil have.

Men hvis du kører $this->setUID(null) inde i DeleteUser metoden, og derefter kører $newUser->getUID(); og får den værdi den havde før, så lyder det mærkeligt. Det kan ikke helt forklares ud fra hvad vi ser.
Avatar billede chrisrj Forsker
10. oktober 2018 - 15:56 #9
Nej nej, du misforstår. :)

Jeg har rettet koden siden starten, efter din anbefaling. :) Det VIRKER! :)

Jeg ville bare høre, om der er en smartere/nemmere måde at gøre det på? :)

Som så altså IKKE kræver ændringer i implementeringen! ;)
Avatar billede Slater Ekspert
10. oktober 2018 - 16:21 #10
Ooh. Ja, det misforstod jeg, beklager.

Mht at gøre det nemmere... Du kan skrive det om så det bliver mindre, f.eks. ved i stedet for at have en metode for hver variabel, så have én metode til alle, f.eks. en
function setProperty($name, $value) - og så køre den i en foreach-loop, hvor du har navnene i et array. Men det ændrer ikke så meget på det, andet end at det fylder lidt mindre.

Hvis det skal være meget mere effektivt, skal det nok gøres udefra, f.eks. ved bare at undlade at bruge objektet - eller at slette det, hvis det er nødvendigt.

Altså når du kører
$u = new User;
// ...
$u->DeleteUser();

Og herfra holder du bare op med at bruge $u, da det ikke længere refererer til noget. Du kan også unset($u); hvis det skal væk, men det er som regel unødvendigt. Det betyder intet at objektet stadig findes i RAM, så længe du undlader at benytte det til noget. Hvis du skal bruge en anden bruger, laver du en ny $u = new User;

Problemet med dette er naturligvis hvis det bliver brugt mange steder, eller af flere forskellige udviklere, fordi koden ikke selv gør det klart, at objektet nu skal opfattes som tomt og ikke bruges. Men er vi derude, vil Arnes forslag med en separat manager give mere mening.
Avatar billede chrisrj Forsker
10. oktober 2018 - 16:27 #11
Tak. :)

Ikke lige det svar jeg havde ønsket, men sådan er det jo tit med php. ;)
Avatar billede arne_v Ekspert
10. oktober 2018 - 18:56 #12
Argumentet for baade en User of en UserManager er separation of concern / single responsibility principle.

De to ting:
* data og funktionalitet af en bruger
* persistering af bruger i database
er to fundamentalt forskellige ting.

De vil skulle aendres af forskellige aarsager.

De vil maaske hoere hjemme i forskellige lag af applikationen (afhaengig af ens lag model).

Udover de principelle problemer saa er der ogsaa nogle praktiske problemer.

Du er rendt ind i et af dem nemlig sletning. Et objekt kan ikke (i PHP) slette sig selv - man kan kun nulstille felter, men det er ikke en reel sletning.

Et andet potentielt problem er operationer paa samlinger af objekter - hvis du f.eks. vil hente et array af alle brugere. Du vil kunne lave en static metode, men saa ville der vaere problemer med to databaser.

Er alt dette saa relevant for din specifikke situation? Det tror jeg!

1) Der er solid erfaring for at kode ofte lever laengere og bruges i flere kontekste end oprindeligt planlagt. Det hack der kun skulle bruges i 6 maaneder inden det nye super system er faerdigt ender med at vaere i drift efter 10 aar og blive brugt til 100 gange stoerre data.

2) Man boer saa vidt muligt altid forsoege at lave god design og god kode. Det er en god vane. Saa kommer det helt automatisk naar det er vigtigt. vender man sig til at lave noget "det virker" kode, saa laerer ,man aldrig at goere det rigtigt.
Avatar billede arne_v Ekspert
10. oktober 2018 - 19:08 #13
For inspiration se evt.:

http://www.vajhoej.dk/arne/articles/phpdb.html

Klasserne:
* T1
* T1DatabaseAccess
* T1DatabaseAccessXxxx

(T1 er saa meget tynd, men der kunne tilfoejes en masse business logik uden at det aendrede paa T1DatabaseAccess klasserne)
Avatar billede chrisrj Forsker
10. oktober 2018 - 22:23 #14
Tak for dine meget detaljerede svar. :)

Her er der dog ikke tale om drift systemer, så levetiden er ikke rigtigt et issue.

Men derfor kan jeg naturligvis godt overveje dine forslag. :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester