PHP a pochopení OOP – PHP – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu
Reklama
Reklama

PHP a pochopení OOP – PHP – Fórum – Programujte.comPHP a pochopení OOP – PHP – Fórum – Programujte.com

 

Spuštěný nový filmový web Filmožrouti.cz — vše o Avengers, Pacific Rim, Thor, Star Wars…
šnek
~ Anonymní uživatel
21 příspěvků
3. 10. 2018   #1
-
0
-

Zdravím přátelé. Snažím se pochopit oop v php, jak se používá, k čemu je dobré. Zkusil jsem si udělat jednoduchý login, chci znát vaše názory, rady, jak to dělat jinak a podobně.

<?php
class login {
    public $id;
    
    public function __construct() {
        if(isset($_SESSION["loginId"])) $this->id = $_SESSION["loginId"]; //pokud sme jiz prihlaseni, tak to rovnou ulozime
    }
    
    function isLogged() {
        if(isset($_SESSION["loginId"])) {
            return true;
        } else {
            return false;
        }
    }
    public function setId(int $id) {
        $this->id = $id;
        $_SESSION["loginId"] = 100;
    }
    public function login($user, $pass) {
        if($user == "jakub" && $pass == "petr") { 
            $this->setId(100);
            return true;
        } else {
            return false;
        }
    }
    
    function logout() {
        unset($_SESSION["loginId"]);
    }
    
    
}

Pokaždé v hlavičce udělám $login = new login(); - pokud už jsem přihlášený, měl bych mít možnost používat na stránkách $login->isLogged(), případně pak dopsání fukce na získání ID kdo je přihlášený a pod.

pokud není přihlášen, mohu to umožnit pomocí $login->login("jméno","heslo"); což vrátí true/false podle toho, zda je kombinace správná...

Je toto správně? Díky za rady

Nahlásit jako SPAM
IP: 185.193.86.–
Kit+14
Guru
3. 10. 2018   #2
-
0
-

#1 šnek
Pro začátek to nevypadá špatně. Zkusím to rozebrat.

Jméno třídy by mělo začínat velkým písmenem. Je to sice jen formalita, ale každý vývojář ti to omlátí o hlavu.

Atribut $id by měl být private. Ovšem připadá mi tak trochu zbytečný - můžeš místo něj uvnitř třídy používat $_SESSION["loginId"]. Třída se tím zpřehlední. S tím souvisí i poslání třídy - je to vlastně obálka (proxy) nad touto superglobální položkou.

Metoda setId() by také neměla být public. Používáš ji přece jen uvnitř třídy.

Return true nebo false je velkým nešvarem ve zdrojácích, čitelnosti to nepomáhá. Metoda isLogged() se dá elegantně zkrátit:

public function isLogged() {
    return isset($_SESSION["loginId"]);
}

Všimni si, že jsem uvedl "public", což je totéž, jako kdyby tam nebylo nic. Používej to u všech veřejných metod nebo u žádné, ať to má řád.

Místo metody $login->isLogged() by mohlo být praktičtější $login->getId(); Až pochopíš výjimky, tak zjistíš, že metoda $login->isLogged() bude zpravidla zbytečná.

Drž se pravidla, že název třídy a instance by měl být podstatným jménem, název metody slovesem. Pak se ti nebude stávat, že budeš mít ve zdrojáku ošklivé $login->login(). Zkus se zamyslet, zdali by nebylo lepší ten objekt pojmenovat třeba $user. Názvy metod na to budou krásně sedět.

Metoda logout() ti nezlikviduje atribut $id. O důvod víc, proč ho nemít.

Nahlásit jako SPAM
IP: 194.228.13.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
šnek
~ Anonymní uživatel
21 příspěvků
3. 10. 2018   #3
-
0
-

Super, díky za postřehy.

Měl bych další otázku - jak implementovat cizí třídu?respektive, dejme tomu, chci mít další třídu messages s funkcema succes a error, principielne messages->succes("vše ok"); a opačně při chybě. Aby se to dalo jednoduše stylovat... Používá se na tohle vůbec třída? protože když funkce, která tě přihlásí nic nemá vracet, jak by o fungovalo? Kdo se má postarat o vypsání chyby, že bylo zadáno špatné jméno/heslo? Třída nebo skript, co volá třídu?

Nahlásit jako SPAM
IP: 185.193.86.–
šnek
~ Anonymní uživatel
21 příspěvků
4. 10. 2018   #4
-
0
-

Další otázka... Pokud správně chápu, třída by měla být nezávislá jiným třídám, jak řešit tahání z DB, když chci používat pdo?

Můžete mi tu prosím udělat příklad jak pomocí PDO udělám funkci na vytáhnutí username z mysql když znám id?

    function getUsername($id) {
        
    }


Jde mi o to, jestli každé volání funkce vytvářet novou instanci s pdo, nebo v hlavičce webu v indexu vytvořit

$db = new pdo(user, pass, db....);

A pak celý projekt používat ve všech třídách pomocí globals $db? přijde mi to jako prasárna...

Případně vytvořit jednu solo třídu, která bude obsluhovat DB? vkládat/tahat data z db? Já vím že tímhle se už dost provokuje MVC, ale potřebuju nejdřív pochopit základy a standarty OOP

Nahlásit jako SPAM
IP: 93.99.138.–
šnek
~ Anonymní uživatel
21 příspěvků
4. 10. 2018   #5
-
0
-

Teď si tu tak trošku píšu sám, omlouvám se :D

napaldo mě tohle řešení, kdy tu instanci předám pomocí konstruktoru do třídy...

    private $id;
    private $_db;
    function __construct(PDO $db) {
        if(isset($_SESSION["loginId"])) $this->id = $_SESSION["loginId"]; //pokud sme jiz prihlaseni, tak to rovnou ulozime
        $this->$_db = $db;
    }
    function isRegister() {
        $sql = 'SELECT username FROM users LIMIT 1';
        if($this->_db->query($sql)->rowCount() > 0) return true;
        return false;   
    }    
    function isLogged() {
        return isset($_SESSION["loginId"]);
    }


Co myslíte?

Nahlásit jako SPAM
IP: 93.99.138.–
gna
~ Anonymní uživatel
716 příspěvků
4. 10. 2018   #6
-
0
-

#5 šnek
JJ, v pohodě.

Nahlásit jako SPAM
IP: 213.211.51.–
šnekr0
Duch
4. 10. 2018   #7
-
0
-

Mno trošku bojuju....

index: 

<?php
 ini_set("display_errors", 1);
    session_start();
    define('SQL_HOST', 'localhost');
    define('SQL_DBNAME', 'oop');
    define('SQL_USERNAME', 'root');
    define('SQL_PASSWORD', '');

    $dsn = 'mysql:dbname=' . SQL_DBNAME . ';host=' . SQL_HOST . '';
    try {
        $_db = new PDO($dsn, SQL_USERNAME, SQL_PASSWORD);
        $_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    } catch (PDOException $e) {
        die('Connection failed: ' . $e->getMessage());
    }

    include "class/login.php";
?>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <?php
            $user = new User($_db);
            
            if(isset($_POST["user"])) {
                $user = $_POST["user"];
                $pass = $_POST["pass"];
                $user->login($user, $pass);    
            }

            //$user->login("jakub", "petr");
            //$user->logout();
            if($user->isLogged())  {
                echo "Test OK!";
            } else {
                echo "<form method=\"post\" action=\"\" > ";
                   echo "Jmeno: <input type=\"text\" name=\"user\"  ><br>";
                   echo "Heslo: <input type=\"text\" name=\"pass\"  ><br>";
                   echo "<input type=\"submit\" name=\"btn\"  ><br>";
                echo "</form>";
            }
            
            echo "<br>";
            
            
        ?>
    </body>
</html>

login.php (přejmenuju na users.php)

<?php
include "messages.php";

class User  extends Messages {
    private $id;
    private $_db;
    
    function __construct(PDO $db) {
        if(isset($_SESSION["loginId"])) $this->id = $_SESSION["loginId"]; //pokud sme jiz prihlaseni, tak to rovnou ulozime
        $this->_db = $db;
    }
    function isRegister() {
        $sql = 'SELECT username FROM users LIMIT 1';
        if($this->_db->query($sql)->rowCount() > 0) return true;
        return false;   
    }    
    function isLogged() {
        return isset($_SESSION["loginId"]);
    }
    
    function setId(int $id) {
        $this->id = $id;
        $_SESSION["loginId"] = 100;
    }
    
    function login($user, $pass) {
        $pass = MD5($pass);
        
        $dotaz = $this->_db->prepare("SELECT id FROM user WHERE username = ?, password = ?");
        $dotaz->execute(array($user,$pass));
        
        if($dotaz->rowCount() > 0) {    //Vyfusnem min. 1 řádek, takze zadal login v poradku 
            $data = $dotaz->fetch();
            $this->setId($data["id"]);
            $this->writeSucces("Přihlášeno!");
        } else {
            $this->writeError("Chybně zadané údaje!");
        }
    }
    
    function logout() {
        unset($_SESSION["loginId"]);
        unset($this->id);
    }  
}

Stránka vrací:

Fatal error: Uncaught Error: Call to a member function login() on string in C:\xampp\htdocs\ooplogin\index.php:32 Stack trace: #0 {main} thrown in C:\xampp\htdocs\ooplogin\index.php on line 32

Co mu vadí? K db připojený jsem...

Nahlásit jako SPAM
IP: 93.99.138.–
MilanL+1
Věrný člen
4. 10. 2018   #8
-
+1
-
Zajímavé

#7 šnekr
řekl bych, že mu vadí ty stejný názvy $user

Edit: myšleno v index.php nejdřív definuješ $user jako objekt User a pak do něj přiřazuješ $_POST["user"]

takže když to dojde na řádek 32 máš v $user ten string z POSTu a ten nemá metodu login

viz. ta chyba

Nahlásit jako SPAM
IP: 91.139.9.–
šnekr0
Duch
4. 10. 2018   #9
-
0
-

#8 MilanL
No jo, taková triviální chyba... boha jeho     

Nahlásit jako SPAM
IP: 93.99.138.–
Kit+14
Guru
4. 10. 2018   #10
-
0
-

#7 šnekr
Vyhýbej se globálním proměnným a konstantám. Tedy i define(). 

$host = 'localhost';
$dbname = 'oop';
$charset = 'utf8';
$username = 'root';
$password = '';
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
$options = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
);
$db = new PDO($dsn, $username, $password, $options);
Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:500e:7140:8f68:cd4f...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
šnekr0
Duch
4. 10. 2018   #11
-
0
-

#10 Kit
Z jakého důvodu? Zrovna údaje k DB jsou předem danné a nemění se...

Jen mimo OOP - je nějaký velký rozdíl mezi echo a print?:D

Nahlásit jako SPAM
IP: 93.99.138.–
Kit+14
Guru
4. 10. 2018   #12
-
0
-

#11 šnekr
Zrovna přihlašovací údaje nechci mít roztahána po celé aplikaci, aby k nim měl přístup i ten, kdo třeba dopíše nějaký plugin. Navíc mi to znemožňuje mít otevřených více databází. Podstatné však je, že tyhle konstanty nikde jinde nepotřebuji, pouze v tom jednom místě. Není tedy ani důvod je mít globální.

Mezi echo a print není rozdíl. Je však zvyklostí používat echo.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:500e:7140:8f68:cd4f...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
šnekr
~ Anonymní uživatel
9 příspěvků
4. 10. 2018   #13
-
0
-

Díky za vysvětlení, pravda...

Ještě jsem se ptal - když se přihlašuju, kdo má psát chybové hlášky? Ta čáíst, co volá funkci třídy, třída, nebo tak jak to mám externí třídou na výpis hlášek? (messages->writeSucces(), messages->writeError()?

Dále jsem narazil na problém... Proč nemůžu použít extends na více tříd? mám třídu Messages na informační zprávy a pak bych chtěl mít solo třídu na hesla? Nebo ty hesla mám nechat zabalený v tříděš s loginem?

Další otázka OOP na příkladu loginu/registrace - udělat pro registraci solo třídu, nebo ji vmísit do téhle třídy login? Nemusí se jednat vždy o veřejnou klasickou registraci, ale i třeba o správu uživatelů administrace....

Nahlásit jako SPAM
IP: 185.193.86.–
Kit+14
Guru
4. 10. 2018   #14
-
0
-

#13 šnekr
Nejlépe pokud třída žádné chybové hlášky nevypisuje, ale jen vyhodí výjimku. Tu pak na vhodném místě mimo třídu zachytíš a zpracuješ.

K čemu potřebuješ více extends? V uvedeném případě nedává smysl ani jeden.

Registrace, login a administrace jsou odlišné činnosti. Zaslouží si samostatné třídy. Mohou však používat společnou třídu pro práci s databází uživatelů. Ani zde dědičnost nevyužiješ.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:500e:7140:8f68:cd4f...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
šnekr
~ Anonymní uživatel
9 příspěvků
4. 10. 2018   #15
-
0
-

#14 Kit
A jak ve třídě vytvořím vyjímku? Nšjak se mi to u php7 nedaří dohledat...

Nahlásit jako SPAM
IP: 185.193.86.–
Kit+14
Guru
4. 10. 2018   #16
-
0
-

#15 šnekr
Na vytvoření výjimky je nejen v PHP příkaz: 

throw new Exception("Chybová hláška");

Je to hodně variabilní. Můžeš si definovat vlastní výjimky třeba takto: 

class MyException extends Exception {
}

Můžeš doplnit i další nepovinné parametetry volání: Kód chyby a zřetězenou výjimku. Pro začátek se bez nich obejdeš.

Vše je popsáno v manuálu:

Výhodou výjimky je, že z ní můžeš vytáhnout hodně informací o tom, co a kde se stalo:

  • jméno výjimky
  • chybová hláška
  • jméno souboru, ve kterém k tomu došlo
  • číslo řádku
  • zřetězené výjimky
  • cokoliv, co si do toho doděláš. Třeba objekt s daty.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:6535:1ca6:118a:9001...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
šnekr
~ Anonymní uživatel
9 příspěvků
4. 10. 2018   #17
-
0
-

#16 Kit
No já nevim, není mi to moc sypatický :D

Nahlásit jako SPAM
IP: 185.193.86.–
Kit+14
Guru
4. 10. 2018   #18
-
0
-

#17 šnekr
Výjimky máš i ve svém příkladu. Hlavně tím oddělíš místo ošetření chyby od místa jejího vzniku. Systematické používání výjimek vede k tomu, že chyby zpracováváš mnohem důkladněji, než kdybys to měl přímo v toku programu. Práce s výjimkami je velmi pohodlná a hlavně nikdy nezapomeneš ošetřit chybový stav.

A ještě něco: Blok try..catch tam vůbec dávat nemusíš. Řádky 

    try {


    } catch (PDOException $e) {
        die('Connection failed: ' . $e->getMessage());
    }

můžeš vyhodit a ponechat jen ty dva uvnitř.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:65bc:4f8d:c2d2:385b...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
šnekr0
Duch
5. 10. 2018   #19
-
0
-

#18 Kit
Takže principielně:

    function login($user, $pass) {
        $dotaz = $this->_db->prepare("SELECT id FROM users WHERE username = ? AND password = ?");
        $dotaz->execute(array($user, $this->hashPwd($pass)));
        
        if($dotaz->rowCount() > 0) {    //Vyfusnem min. 1 řádek, takze zadal login v poradku 
            $data = $dotaz->fetch();
            $this->setId($data["id"]);
        } else {
           //$this->writeError("Chybně zadané údaje!");
           throw new Exception("Chybne udaje!");
       
        }
    }
            if(isset($_POST["user"])) {
                $f_user = $_POST["user"];
                $f_pass = $_POST["pass"];
                try {
                    $user->login($f_user, $f_pass);    
                } catch (Exception $e){
                    echo $e->getMessage();
                }        
            }

je to v pořádku?

Funguje to, spíš mě zajímá, jestli se to takhle dělá i v praxi...

Nahlásit jako SPAM
IP: 93.99.138.–
peter
~ Anonymní uživatel
3395 příspěvků
12. 10. 2018   #20
-
0
-

Hele, session nebo post dej to jako parametr, treba do construct nebo promenne. Ale urcite s tim nepracuj uvnitr.

function ... (...)
{
if(isset($_POST["user"]))
}

vs
function ... (..., $post) // nebo jeste pouzivam $form, protoze vstupem mam formular z html
{
if(isset($post["user"]))
}

Nahlásit jako SPAM
IP: 2001:718:2601:258:39f6:5914:e731:14df...–
Kit+14
Guru
12. 10. 2018   #21
-
0
-

#19 šnekr
Dá se to napsat mnohem jednodušeji se stejným výsledkem: 

<?php
function login($user, $pass) {
    $dotaz = $this->_db->prepare("SELECT id FROM users WHERE username = ? AND password = ?");
    $dotaz->execute(array($user, $this->hashPwd($pass)));
    if ($dotaz->rowCount() == 0) {
        throw new Exception("Chybne udaje!");
    }
    $data = $dotaz->fetch();
    $this->setId($data["id"]);
}

if (isset($_POST["login"])) {
    $user->login($_POST["user"], $_POST["pass"]);    
}

Když budeš používat obrácené podmínky, tak ti zmizí spousta zbytečných "else". Všimni si, že jsem nepoužil isset() na políčko "user", ale na tlačítko "login". To ti umožní používání více tlačítek na jednom formuláři a také více funkcí pro stejný typ vstupů.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:7116:e8b9:1364:29bc...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
šnekr0
Duch
15. 10. 2018   #22
-
0
-

#21 Kit
Jasný chápu - proč nepoužíváš try {} catch {}? Potom to vypíše tu vyjímku celou, vč souborua  podbně.... Já chci aby se zobrazila jen ta samotná hláška :-)

#20 peter
Npoužívám globální proměnné uvnitř...

Nahlásit jako SPAM
IP: 46.135.30.–
Kit+14
Guru
15. 10. 2018   #23
-
0
-

#22 šnekr
try .. catch používám. Začátečníci si však často stěžují, že jim to připadá nepřehledné a že starý způsob je jednodušší. Proto jim radím, ať to zkusí bez toho. Výsledek je podobný die(), ale je mnohem popisnější. Všimni si, že jsi vůbec netestoval, zda se správně provedlo připojení k databázi nebo zda SQL dotaz neselhal. Výjimky to udělaly za tebe. U prototypů bývá lepší, když je neošetříš - poskytne ti to cenné informace pro ladění.

V ostré aplikaci je naopak vhodné výjimky ošetřit.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:c01e:f95b:bfb6:90fa...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
šnekr0
Duch
15. 10. 2018   #24
-
0
-

#23 Kit
s tím douhlasím, ale zrovna tam, kde chci vracet reálnou chybu (ne programovou) tak chci vypsat jen chybu - jako například, když se někdo registruje a je již zaregistrovaný mail...

Nahlásit jako SPAM
IP: 185.193.86.–
Kit+14
Guru
16. 10. 2018   #25
-
0
-

#24 šnekr
Však to už máš vyřešeno odchycením a vypsáním výjimky. Stačí jen místo "echo" zalogovat vně objektu třídy User.

Pokud bys chtěl logovat uvnitř, tak objekt $log injektuješ. Beze změny třídy User tak budeš moct definovat, zda a kam se bude logovat.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:4c36:7341:9518:4435...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Zjistit počet nových příspěvků

Přidej příspěvek

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 1 registrovaný, 19 hostů

Podobná vlákna

PHP OOP — založil Neony

PHP OOP začátečník — založil th

Mé dotazy na OOP v PHP — založil polonium

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032018 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý