Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] Skrypt rejestracji (OOP) - prośba o poprawę kodu
Forum PHP.pl > Forum > Przedszkole
Testosteron
Witajcie!

Chcę nauczyć się programowania obiektowego. Niestety, kursy internetowe opierają się na nieco głupich przykładach, w stylu:
- zaszczekaj burku
- hau hau
Nie ma to przełożenia na realne problemy z jakimi stykamy się w programowaniu. W mojej książce, "PHP i MySQL. Vademecum profesjonalisty" także programowanie obiektowe nie zostało dobrze opisane. Postanowiłem więc spróbować napisać coś prostego. W moim przypadku był ro system rejestracji. Skrypt działa w 100%, chociaż nie jest dokończony (nie ma walidacji hasła, a walidacja loginu też nie jest w pełni skończona). Chodzi mi raczej o samą zasadę działania. Od razu mówię, że jest to mój PIERWSZY, obiektowy projekt pisany bez żadnego wzoru. Zależy mi na tym, żeby ktoś poradził, co należy zmienić.
  1. <?php
  2. /* class connect{
  3.   function __construct(){
  4.   $polaczenie = @new mysqli('localhost', 'root', 'haslo', 'login');
  5.   if (mysqli_connect_errno() != 0){
  6.   echo '<p>Wystąpił błąd połączenia: ' . mysqli_connect_error() . '</p>';
  7.   }
  8.   }
  9. }
  10. */
  11.  
  12. class formularz{
  13. function wyswietl(){
  14. echo"<table>
  15. <form action='register.php' method='post'>
  16. <tr><td>Login:</td><td><input type='text' name='login'></td></tr>
  17. <tr><td>Password:</td><td><input type='password' name='pass'></td></tr>
  18. <tr><td><input type='submit' value='zarejestruj'></td></tr></form>
  19. </table>";
  20. }
  21.  
  22. }
  23.  
  24. class walidacja extends formularz{
  25.  
  26. //dodawanie usera
  27. function __construct(){
  28. $mysqli = new mysqli('localhost', 'root', 'haslo', 'login');
  29. $login = $mysqli->real_escape_string($_POST['login']);
  30. $pass = $mysqli->real_escape_string($_POST['pass']);
  31.  
  32. if (empty($login) || empty($pass) ){
  33. $this->wyswietl();
  34. } else {
  35. if ($this->sprawdz_login($login) ){
  36. $query = $mysqli->query("INSERT INTO login VALUE('" . $login . "', '" . $pass . "')");
  37. if ($query){
  38. echo 'user został dodany';
  39. } else {
  40. echo 'blad';
  41. }
  42. }
  43.  
  44. }
  45. }
  46.  
  47. //Poprawność loginu
  48. function sprawdz_login($login){
  49. $login = $_POST['login'];
  50. if (strlen($login) < 4){
  51. echo 'login musi miec przynajmniej 4 znaki';
  52. } else {
  53. return true;
  54. }
  55. }
  56. }
  57.  
  58.  
  59.  
  60. $formularz = new walidacja;
  61.  
  62. ?>

Na początku chciałem napisać klasę connect (obecnie jest zawarta w komentarzu), jednak miałem problem z wykorzystaniem jej, tzn. zależy mi, żeby w jednej klasie zawrzeć wszystkie dane dotyczące logowania do mysql i później żebym mógł w innych klasach wykorzystywać wszystkie metody mysqli. Niestety miałem z tym problem. Jeżeli ktoś wie jak to zrobić, to byłbym także wdzięczny za odpowiedź.

pozdrawiam smile.gif
ctom
do przemyślenia : co ma wspólnego "class walidacja" z DB ?

pomocny link do Twoich pytań dependency-injection
SmokAnalog
Po pierwsze takie małe kosmetyczne sprawy:
  • Nazwy klas zwyczajowo powinny zaczynać się od wielkiej litery
  • Nazywaj klasy, zmienne i metody po angielsku


Oprócz tego masz logikę dziwną. Klasa walidacja nie rozszerza w logiczny sposób klasy formularz. To powinna być jedna klasa, albo klasa walidacja powinna przyjmować obiekt formularza jako parametr np. w konstruktorze. Ewentualnie na odwrót, ale tak wydaje mi się to bardziej rozsądne, bo klasa formularz ma sens bez walidacji, a walidacja bez formularza już niezbyt.

Fajnie jak pouczysz się wyjątków, bo wyrzucanie błędów w echo to bardzo zły pomysł.
Testosteron
  1. <?php
  2. /* class connect{
  3. function __construct(){
  4. $polaczenie = @new mysqli('localhost', 'root', 'pass', 'login');
  5. if (mysqli_connect_errno() != 0){
  6. echo '<p>Wystąpił błąd połączenia: ' . mysqli_connect_error() . '</p>';
  7. }
  8. }
  9. }
  10. */
  11.  
  12. class formularz{
  13.  
  14.  
  15. //dodawanie usera
  16. function __construct(){
  17. $mysqli = new mysqli('localhost', 'root', 'pass', 'login');
  18. $login = $mysqli->real_escape_string($_POST['login']);
  19. $pass = $mysqli->real_escape_string($_POST['pass']);
  20.  
  21. if (empty($login) || empty($pass) ){
  22. $this->wyswietl();
  23. } else {
  24. if ($this->sprawdz_login($login) ){
  25. $query = $mysqli->query("INSERT INTO login VALUE('" . $login . "', '" . $pass . "')");
  26. if ($query){
  27. echo 'user został dodany';
  28. } else {
  29. echo 'blad';
  30. }
  31. }
  32.  
  33. }
  34. }
  35.  
  36. //Poprawność loginu
  37. function sprawdz_login($login){
  38. $login = $_POST['login'];
  39. if (strlen($login) < 4){
  40. echo 'login musi miec przynajmniej 4 znaki';
  41. } else {
  42. return true;
  43. }
  44. }
  45.  
  46. //wyświetlanie formularza
  47. function wyswietl(){
  48. echo"<table>
  49. <form action='6.php' method='post'>
  50. <tr><td>Login:</td><td><input type='text' name='login'></td></tr>
  51. <tr><td>Password:</td><td><input type='password' name='pass'></td></tr>
  52. <tr><td><input type='submit' value='zarejestruj'></td></tr></form>
  53. </table>";
  54. }
  55.  
  56. }
  57.  
  58.  
  59.  
  60. $formularz = new formularz;
  61.  
  62. ?>


Cytat
(...) albo klasa walidacja powinna przyjmować obiekt formularza jako parametr np. w konstruktorze

Chodzi o to, żeby utworzyć obiekt klasy formularz i wywołać metodę wyświetl w konstruktorze?

Chyba cały czas myślę proceduralnie. W sumie rano przeczytałem rozdział dotyczący OOP, wykonałem kilka ćwiczeń, a wieczorem napisałem ten skrypt dla treningu. Wiem co to jest dziedziczenie. Często podaje się przykłady w stylu - klasy rower i samochód dziedziczą od klasy pojazd, itp. Nie jest to jednak typowy problem z którym stykamy się w programowaniu. W jakich przypadkach najczęściej korzysta się z dziedziczenia? W tej chwili do głowy przychodzi mi tylko tworzenie bazy danych. Tam faktycznie pewne pola mogą być wspólne i są logicznie połączone smile.gif .
Turson
Dalej masz te same błędy:
Nazewnictwo klas
Ogólnie stosuje się camelCase w nazwach metod i dobrym nawykiem są angielskie nazwy.
Echo w metodach.
Samo zapytanie insert powinno być odzielną metodą.
Do obsługi bazy danych, np. nawiązywanie połączenia czy pobranie obiektu bazy napisz osobną klasę ale nie dziedzicz jej, a niech metoda getDb() będzie statyczna.

Cytat
Często podaje się przykłady w stylu - klasy rower i samochód dziedziczą od klasy pojazd, itp. Nie jest to jednak typowy problem z którym stykamy się w programowaniu.

Przykład może nie z życia wzięty, ale poprawny. Przykład: RegisterController może dziedziczyć głowny kontroler aplikacji.
Testosteron
* Nazewnictwo to mały pikuś. Ten skrypt miał być wyłącznie ćwiczeniem.
* Echo użyłem, ponieważ nie uczyłem się jeszcze obsługi wyjątków.
* Co do insert - poprawię to.
* Próbowałem napisać klasę do łączenia z mysql, ale cos mi nie szło, tzn. nie wiedziałem jak korzystać z wbudowanych metoda mysqli. Kod, który próbowałem napisać jest w komentarzu.
aras785
Odnośnie ECHO to nigdy nie używaj tego w metodach ponieważ funkcja powinna zwracać jakąś wartość, a co znią później zrobisz to od Ciebie zależy: sprawdzić warunkiem czy też wyświetlić:

Przykład:

  1. <?php
  2. class Car
  3. {
  4. private $model;
  5.  
  6. public function __construct() {
  7.  
  8. }
  9. public function setModel($model) {
  10. $this->model = $model;
  11. }
  12. public function getModel() {
  13. return $this->model;
  14. }
  15. }
  16.  
  17.  
  18. $car = new Car;
  19. $car->setModel('audi');
  20. //teraz decyduje co chce z wartoscia zrobic
  21. if($car->getModel()=='audi') echo 'Jest OK';else echo 'Jest ŹLE';
  22.  
  23. //wyświetlenie
  24. echo $car->getModel();



U Ciebie z danymi nic nie możesz zrobić bo metody nic nie zwracają...
SmokAnalog
Dziedziczenie jest wspaniałe i daje mnóstwo korzyści. Jedną z moich ulubionych jest tzw. polimorfizm. Jako że nie lubisz przykładów nieinformatycznych (ja np. wolę takie na psach, truskawkach itd. biggrin.gif), to spróbuję podać informatyczny. Ba, podam nawet przykład dla klasy formularzy.

Prędzej czy później będziesz chciał zrobić obiekty pól formularza. To jest doskonałe miejsce dla dziedziczenia, bo one będą miały jakieś części wspólne, na przykład:
  1. class InputText extends InputField {...}
  2. class InputCheckbox extends InputField {...}
  3. // teraz uważaj:
  4. class InputTextarea extends InputText {...}

Obiekt generujący textarea mógłby dziedziczyć po obiekcie generującym zwykłe pole tekstowe, bo będą miały prawdopodobnie wiele wspólnego, a jedną z niewielu różnic będzie metoda, która wypluwa ich HTML.

W klasie formularza mógłbyś mieć metodę, która dodaje pole na zasadzie:
  1. $form = new Form;
  2. $textarea = new InputTextarea;
  3.  
  4. $form->add($textarea);


A definicja metody add w klasie Form mogłaby wyglądać tak:
  1. public function add(InputField $field) {...}


Tutaj działa nasz polimorfizm, bo mówisz metodzie add, że może przyjmować dowolne pole. Każda z naszych powyższych klas InputText, InputCheckbox i InputTextarea to instancje klasy InputField, bo każda po niej dziedziczy. InputText i InputCheckbox bezpośrednio, a InputTextarea dziedziczy po InputText, czyli też jest dzieckiem klasy InputField smile.gif
Testosteron
Nie wiem, czy dobrze Cię zrozumiałem. Mogę stworzyć klasę form, która odpowiada za zwracanie pól formularza. Jej metoda mogłaby przyjmować parametr dotyczący typu pola, czyli - text, password, itp. Inna metoda tej klasy mogłaby ogólnie tworzyć formularz, a więc, np. ustawiałaby metodę get, bądź post i wskazywała na plik do którego mają zostać przesłane dane. Kolejne klasy dziedziczyłyby z tej klasy i odnosiłyby się do konkretnych typów pól formularza. Zawierałyby np. walidację wprowadzonych przez użytkownika danych i zwracałyby true bądź false

Dodatkowo metoda klasy form sprawdzałaby, czy dane zostały wcześniej przesłane. Zwracałaby wartość true bądź false. Poniżej deklaracji wszystkich klas mógłbym stworzyć instrukcję warunkową, która sprawdzałaby, czy dane zostały przesłane. Jeśli nie (a więc odpowiednia metoda zwróci wartość false), tworzy obiekty typu - login, password, mail, itp. W przeciwnym wypadku następuje sprawdzenie poprawności danych i jeśli wszystko jest dobrze, następuje zapisanie ich w bazie danych. W takim układzie tworząc kolejne formularze na stronie (np. komentarze, wyszukiwarka), mógłbym skorzystać z klas stworzonych wcześniej. Oczywiście musiałbym dodać nowe zapytanie, być może nową klasę weryfikującą poprawność danych, ale pracy byłoby o wiele mniej.

Uważasz, że tak byłoby dobrze?
pedro84
@Testosteron - nie. Przeczytałeś w ogóle post oraz listingi podane przez @SmokAnaloga?

Uproszczając: masz jedną klasę, Input, która zawiera wszelkie metody wspólne dla wszystkich typów kontrolek formularzy, np. Input::getName(). Tworzysz sobie x klas, dla każdego typu kontrolek, które chcesz wykorzystać: np. Checkbox, Text, Textarea, które dziedziczą po klasie Input.
Testosteron
Czytałem, ale przed samym wyjściem. A metody walidacji wstawić w klasach konkretnych inputów?
pedro84
Walidacja moim zdaniem powinna być osobnym bytem. Stosuj zasadę jednej odpowiedzialności (ang. Single responsibility principle).

Za Wikipedią:
Cytat
Martin utożsamia odpowiedzialność klasy z powodem do jej modyfikacji. Możemy rozważyć moduł, który generuje i drukuje raport. Odpowiada on za dwa procesy, a tym samym mogą wystąpić dwa powody do jego modyfikacji. Po pierwsze, może zmienić się treść generowanego raportu, po drugie ? format, w jakim jest on drukowany. Zasada pojedynczej odpowiedzialności mówi, że oba te procesy powinny być niezależne i zaimplementowane w postaci dwóch oddzielnych klas lub modułów, które komunikują się ze sobą przy pomocy publicznych interfejsów.


Zobacz sobie jak to jest rozwiązane np. w komponencie Validation z Symfony.
Testosteron
Ściągnąłem Symfony. Muszę przyznać, ze ten kod jest dla mnie jest trochę skomplikowany. Zauważyłem ponadto , że większość klas dziedziczy od sfValidatorRegex. Ona z kolei dziedziczy od sfValidatorString, itp. Jeszcze dobrze nie rozumiem zagadnień związanych z OOP. Myślałem, żeby nieco poduczyć się Javy. Nie tylko nauczę się lepiej programować obiektowo, ale ta wiedza też się nie zmarnuje:

1. Coraz więcej stron posiada mobilne wersje stron.
2. Często strony tworzą aplikacje, które mają za zadania rozreklamować daną stronę.
3. Czasami przydałoby mi się stworzyć aplikację desktopową, itp.

Chciałbym rozwijać się głównie w programowaniu stron WWW (znam też trochę jQuery, a JS musiałbym sobie przypomnieć). Moją największą bolączką w PHP jest właśnie OOP, a wydaje mi się, że Java jest dobrym językiem do nauki obiektówki.

PS. Jak znajdę chwilę czasu to postaram się stworzyć ten skrypt jeszcze raz, według wskazówek, które mi udzieliliście.
pedro84
Chodziło mi o Symfony 2.

Najpierw musisz poznać podstawy programowania obiektowego, a dopiero potem poszczególne implementacje w danych językach. PHP nie jest już tak tragiczny w implementacji OOP jak parę lat temu (co nie znaczy, że nie mogłoby być lepiej).

PS. Co ma Java do stron mobilnych?
Testosteron
Chodziło mi o aplikacje na urządzenia mobilne. Dużo stron posiada takie aplikacje, które ułatwiają korzystanie z nich, np. FB, nk, Kwejk, Demotywatory, itp.

Natrafiłem na pewien problem w kodzie. Otóż - muszę stworzyć klasę, która sprawdza, czy dane zostały przesłane z formularza (następuje ich weryfikacja) czy nie (wyświetlenie formularza). W poprzednim kodzie sprawdzałem czy którakolwiek ze zmiennych globalnych nie została wysłana. W nowym kodzie mogę stworzyć dowolną ilość kontrolek formularza o dowolnych nazwach. Jak więc zrobić taką klasę? Może po prostu zrobić to już poza klasami?

Faktycznie, ściągnąłem starszą wersję. W sumie za bardzo nie wczytałem się na ich stronie, ale na pierwszy rzut oka widzę, ze jest trochę zabawy z instalacją Symphony 2. Trzeba zainstalować Compozera, itp. W Zend pewnie też są w miarę porządnie napisane klasy walidacji danych. Jutro ściągnę Zenda albo ę Symphony 2, bo dzisiaj jestem już zmęczony.

Trochę poprawiłem kod, ale na razie zrobiłem tylko szkielet.
  1. <?php
  2. class form{
  3. private $name, $value;
  4.  
  5. public function setName($name){
  6. $this->name=$name;
  7. }
  8. public function getName(){
  9. return $this->name;
  10. }
  11. public function setValue($name){
  12. $this->value=$value;
  13. }
  14. public function getValue(){
  15. return $this->value;
  16. }
  17.  
  18. public function newForm($method, $file){
  19. echo '<form action="' . $file . '" method="' . $method . '" />';
  20. }
  21.  
  22. public function finish(){
  23. echo '</form>';
  24. }
  25. }
  26.  
  27. class inputText extends form{
  28. public function createText(){
  29. return '<input type="text" name="' . $this->getName() . '" />';
  30. }
  31. }
  32.  
  33. class inputPass extends form{
  34. public function createPass(){
  35. return '<input type="password" name="' . $this->getName() . '" />';
  36. }
  37. }
  38.  
  39. class inputSubmit extends form{
  40. public function createSubmit(){
  41. return '<input type="submit" value="' .$this->getValue(). '" />';
  42. }
  43. }
  44. class validation{
  45. private $variable, $type;
  46.  
  47. public function setValidation($variable, $type){
  48. $this->variable = $variable;
  49. $this->type = $type;
  50. }
  51. public function validateForm(){
  52. htmlspecialchars($this->variable); //na razie nie łączę się z bazą danych, więc powinno mi to wystarczyć
  53. switch ($this->type){
  54. case 1: //nr 1 oznacza login
  55. {
  56. if (strlen($this->variable) < 3){
  57. return false;
  58. } else {
  59. return true;
  60. }
  61. }
  62. //case 2:
  63. //etc
  64. }
  65.  
  66. }
  67. }
  68.  
  69. class register{
  70. private $login, $pass;
  71.  
  72. public function setRegister($login, $pass){
  73. $this->login = $login;
  74. $this->pass = $pass;
  75. }
  76.  
  77. public function finalRegister(){
  78. return 'Zarestrowałem konto o nicku ' . $this->login . '. Jego hasło to: ' . $this->pass;
  79. }
  80. }
  81.  
  82. if (empty($_POST['login']) || empty($_POST['pass']) ){
  83. $form = new form;
  84. $form->newForm('POST', '8.php');
  85. $login = new inputText;
  86. $login->setName('login');
  87. echo $login->createText();
  88. $pass = new inputPass;
  89. $pass->setName('pass');
  90. echo $pass->createPass();
  91. $submit = new inputSubmit;
  92. $submit->setValue('Wyslij');
  93. echo $submit->createSubmit();
  94. $form->finish();
  95. } else {
  96. $valid = new validation;
  97. $valid->setValidation($_POST['login'], 1);
  98. if ($valid->validateForm() == false){
  99. echo "Nie moge zarejestrowac tego usera";
  100. } else {
  101. $reg = new register;
  102. $reg->setRegister($_POST['login'], $_POST['pass']);
  103. echo $reg->finalRegister();
  104. }
  105. }
  106. ?>


Nikt już się nie wypowie?
Pyton_000
Drobne uwagi co do kodu.
W klasach dziedziczących powinieneś mieć 1 metodę która nazywa się createInput (jego rodzaj definiuje przecież typ obiektu) Nie ma sensu tworzenia oddzielnych metod dla każdej z nich. Dodatkowo setName powinno się odnosić do formularza a nie do input. Nazwę input przekazuj w konstruktorze obiektu i ustawiaj w klasie. Dzięki temu masz każdy obiekt nazwany i nie musisz stosować setName, getName.

Poza tym ja bym zrobił coś na zasadzie:
- Jest sobie obiekt Form. Posiada on kolekcję inputów. coś na zasadzie:
  1. $form = new Form('FormularzNowościowy');
  2. $form->put(new InputText('nazwa'));
  3. ...
  4. if(isset($_POST)) {
  5. $validateRules = new Validate()->addRule('nazwaInput', array('nazwa_reguly' => 'cos'));
  6. $form->validate($validateRules);
  7. ....
  8. }
  9. ....
  10. $form->show();


To tak na szybko.
golabow
Może pomyśl o klasie abstrakcyjnej, wydzielisz do niej wszystkie właściwości i wymusisz interfejs metodą abstrakcyjną. Zauważ że wszystkie te klasy własnie robią podobną czynność. Potem wystarczy użyć polimorfizmu i masz ładny kod.
Testosteron
Macie rację. Postaram się poprawić kod. Tylko, że klasa form sama w sobie posiada metody, tworzące znacznik <form> (wraz z atrybutami) oraz znacznik zamykający. Jeśli stworzę klasę abstrakcyjną to nie będę mógł stworzyć obiektu tej klasy i korzystać z jej metod w taki sposób jak to robię obecnie.
pedro84
A właściwie po co Ci metoda, w której klasa pluje HTMLem, który możesz napisać w widoku?
Testosteron
No niby mogę, ale z drugiej strony w widoku można napisać cały formularz. Jeżeli piszę klasę formularza to mam wrażenie, że bez tych dwóch metod byłaby niepełna.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.