• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Zrozumieć obiektowość

VPS Starter Arubacloud
+1 głos
352 wizyt
pytanie zadane 25 sierpnia 2023 w PHP przez juuunior Początkujący (460 p.)

Witam ponownie

Próbuje polepszyć jakość kodu który piszę więc zainteresowałem się klasami i tu kilka pytań do Was:

- czy poprawnie rozumiem myślenie obiektowe ? pewnie nie... ale gdzie robię błędy ? 

- czytałem że kiepski programista daje dużo ifów , tak się składa że jak pisałem sklep było ich tak dużo że nie mam ochoty wracać do tego kodu aby coś przerobić ;)  więc chcąc czy nie trzeba coś zmienić.

- jak więc uniknąć ifa przy wyborze między klasą modul2 a modul3 ?   

dzięki za jakąkolwiek pomoc

<?php
 ////////////////////// MODEL //////////////////////////
 
abstract class modul {
  public $div; 
  public $div2;
  public $value;
   
  function __construct($div, $div2, $value)
  {
    $this->div = $div;
    $this->div2 = $div2;
    $this->value = $value;
  }

}

 //////////////////////// LOGIC ///////////////////////////
 class modul1 extends modul {
 
function gethtml(){
    $html1 = '<div class="'.$this->div.'">';
    $html1 .= '<div class="'.$this->div2.'">'.$this->value.'</div>';
    $html1 .= '</div>';   
    return $html1;
  }
}

class modul2 extends modul {
 
  function gethtml(){
      $html2 = '<div class="'.$this->div.'">';
      $html2 .= '<div class="'.$this->div2.'">'.'<div class="kafelek">'.$this->value.'</div>'.'</div>';
      $html2 .= '</div>';   
      return $html2;
    }
  }

  class modul3 extends modul {
 
    function gethtml(){
        $html2 = '<div class="'.$this->div.'">';
        $html2 .= '<div class="'.$this->div2.'">'.'<div class="kafelek2">'.$this->value.'</div>'.'</div>';
        $html2 .= '</div>';   
        return $html2;
      }
    }
 
 //////////////////////// LOGIC /////////////////////////////

$menu = 'MENU';
 $menu .= ' .itp';
 $modul1 = new modul1('container', 'pod', $menu);
 echo $modul1->gethtml();

 $value = 'bebechy content';
 $modul2 = new modul2('container', 'pod', $value);
 echo $modul2->gethtml();

 $stopka = 'STOPKA';
 $modul3 = new modul1('container', 'pod', $stopka);
 echo $modul3->gethtml();
?>
 
.container{
        max-width: 1000px;
        margin-left: auto;
        margin-right: auto;
      }
      .pod{
        width: 100%;
        background-color: green;
        color: white;
        text-align: center;
        align-items: center;
        justify-content: center;
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        gap: 60px;
      }
    
      .kafelek{
        height: 500px;
        width: 100%;
        background-color:#99ff99;
        color: black;
        text-align: center;
        align-items: center;
        justify-content: center;
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        gap: 60px;
      }
      .kafelek2{
        height: 200px;
        width: 100%;
        background-color:#99ff99;
        color: black;
        text-align: center;
        align-items: center;
        justify-content: center;
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        gap: 60px;
      }

 

1
komentarz 25 sierpnia 2023 przez SzkolnyAdmin Szeryf (88,920 p.)

" czytałem że kiepski programista daje dużo ifów "

Nie jest tak źle, teraz przed tobą szybki zjazd z górki na prawo :)

2 odpowiedzi

+1 głos
odpowiedź 26 sierpnia 2023 przez wizarddos Nałogowiec (26,590 p.)

- czy poprawnie rozumiem myślenie obiektowe ? pewnie nie... ale gdzie robię błędy ? 

Nie jest źle, jedyne co proponuję poprawić to jakoś wrzucić funckję `gethtml()` do klasy `module` a nie redefiniować ją bez przerwy w każdej klasie

- czytałem że kiepski programista daje dużo ifów , tak się składa że jak pisałem sklep było ich tak dużo że nie mam ochoty wracać do tego kodu aby coś przerobić ;)  więc chcąc czy nie trzeba coś zmienić.

W samych ifach nie ma nic złego, to bardzo przydatna konstrucja. Może autorowi chodziło o zagieżdżanie ifów? To też szczerze mówiąc zbyt wielkiego znaczenia przy małych kodach nie ma, ale przy dużych projektach tworzy się wiele (czasem nawet po 30-40) poziomów. To akurat sprawia że kod jest mniej czytelny, ale czasem krótszy

 

Tu się akurat posłużę przykładem - ten kod

if(!empty($login) || !empty($password)){
   if(strlen($password) > 8){
      $db = new PDO($db_dsn, $db_user, $db_pass);

      $sql = "SELECT * FROM `users` WHERE `login`=?";

      $stmt = $db->prepare($sql);
      $stmt->execute([$login]);
      $result = $stmt->fetch(PDO::FETCH_ASSOC);
      if!$stmt->rowCount()){
         if(password_verify($password, $result['password'])){
            header("Location: secret.php");
         }
      }
   }
}

Jest lekko mniej mniej czytelny i na pewno cięższy w utrzymaniu  niż ten

if(empty($login) || empty($password)){
    $isValid = false;
    $errorMsg = "Login and/or Password can't be empty";
}

if(strlen($password) < 8){
    $isValid = false;
    $errorMsg = "Password must have at least 8 characters" ;
}

if(!$isValid){
    $_SESSION['errorMsg'] = $errorMsg;
    header("Location: index.php");
    exit();
}

$db = new PDO($db_dsn, $db_user, $db_pass);

$sql = "SELECT * FROM `users` WHERE `login`=?";

$stmt = $db->prepare($sql);
$stmt->execute([$login]);

$result = $stmt->fetch(PDO::FETCH_ASSOC);
if(!$stmt->rowCount()){
    $isValid = false;
    $errorMsg = "Incorrect username or password";
}else{
    if(!password_verify($password, $result['password'])){
        $isValid = false;
        $errorMsg = 'Incorrect username or password';
    }
}


if(!$isValid){
    $_SESSION['errorMsg'] = $errorMsg;
    header("Location: index.php");
    exit();
}

Pomimo tego że jest lekko dłuższy, bez ogromnego zagnieżdżania ifów czytamy jak normalnie od lewej do prawej, a nie na skos

Poza tym, gdy chcielibyśmy dodać nowy warunek (np. logowanie bez hasła albo warunek aktywowania konta lub coś w tym stylu), nie trzeba grzebać w strukturze, tylko wystarczy dopisać if'a w odpowiednim miejscu

 

To są małe przykłady, więc nie jest to aż tak widoczne, ale jak wyżej wspomniałem. Przy większym codebase'ie jest coraz ciężej

+1 głos
odpowiedź 26 sierpnia 2023 przez VBService Ekspert (255,840 p.)
edycja 27 sierpnia 2023 przez VBService

Twoje podejście obiektowe jak na początek jest w większości poprawne. Stworzyłeś abstrakcyjną klasę bazową modul, która posiada właściwości i metodę konstruktora, a następnie dziedziczą po niej klasy modul1, modul2 i modul3. Każda z tych klas ma swoją metodę gethtml() do generowania kodu html. Ogólnie rzecz biorąc, jest to dobry krok w kierunku tworzenia bardziej zorganizowanego kodu.

czytałem że kiepski programista daje dużo ifów

To prawda, że nadmiar instrukcji warunkowych może sprawić, że kod staje się trudny do zarządzania i rozbudowy. Tworzenie hierarchii klas, jak to zrobiłeś, jest krokiem w dobrą stronę.

Zwróć uwagę na konwencje nazewnicze w PHP. Nazwy klas powinny zaczynać się od wielkiej litery, a metody i zmienne od małej litery.

Możesz również wprowadzić drobne usprawnienia w klasach modułów, takie jak przeniesienie powtarzającego się kodu do klasy bazowej, unikając duplikacji kodu.

Propozycja zmian w Twoim kodzie:

<?php
  ////////////////////// MODEL //////////////////////////

  abstract class BodyModul {
    public $containerClass;
    public $contentClass;
    public $content;

    function __construct($containerClass, $contentClass, $content) {
      $this->containerClass = $containerClass;
      $this->contentClass   = $contentClass;
      $this->content        = $content;
    }

    protected function generateHtml($innerHtml, $parentTag='div', $innerTag='div') {
      return '<' . $parentTag . ' class="' . $this->containerClass . '">
                <' . $innerTag . ' class="' . $this->contentClass . '">' . $innerHtml . '</' . $innerTag . '>
              </'.$parentTag.'>';
    }

    abstract function getHtml();
  }

  //////////////////////// LOGIC ///////////////////////////
  class HeaderModule extends BodyModul {
    function getHtml() {
      if (is_array($this->content)) {
        $menu = array_map(function($item) {
          return '<li><a href="'.$item['href'].'">'.$item['text'].'</a></li>';
        }, $this->content);

        return $this->generateHtml('<ul>'.implode('', $menu).'</ul>', 'header', 'nav');
      } else {
        return $this->generateHtml($this->content, 'header');
      }
    }
  }

  class MainModule extends BodyModul {
    function getHtml() {
      return $this->generateHtml($this->content, 'main');
    }
  }

  class FooterModule extends BodyModul {
    function getHtml() {
      return $this->generateHtml($this->content, 'footer');
    }
  }

  //////////////////////// LAYOUT /////////////////////////////
  $menu = [
    [
        "text" => "Google",
        "href" => "https://www.google.com"
    ],
    [
        "text" => "Facebook",
        "href" => "https://www.facebook.com"
    ],
    [
        "text" => "Twitter",
        "href" => "https://www.twitter.com"
    ],
    [
        "text" => "GitHub",
        "href" => "https://www.github.com"
    ],
    [
        "text" => "LinkedIn",
        "href" => "https://www.linkedin.com"
    ]
  ];
  $header = new HeaderModule('container', 'horizontal', $menu);
  echo $header->getHtml();

  $text = 'Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor';
  $main = new MainModule('container', 'content', $text);
  echo $main->getHtml();

  $text = 'STOPKA';
  $footer = new FooterModule('container', null, $text);
  echo $footer->getHtml();
?>

<!-- dla prezentacji -->
<style>
  * {
    margin: 0;
    padding: 0;
  }
  html, body {
    padding: .5rem;
  }
  .container {
    max-width: 1000px;
    margin: .5rem auto;
    background-color: green;
  }
  header, main, footer {
    width: 100%;
  }
  header nav ul {
    display: flex;
    gap: .5rem;
    list-style-type: none;
  }
  header nav ul a {
    display: block;
    text-decoration: none;
    padding: .5rem;
    color: white;
  }
  header nav.horizontal ul {
    flex-direction: row;
  }
  header nav.vertical ul {
    flex-direction: column;
  }
  main .content {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 50dvh;
  }
  footer {
    display: flex;
    justify-content: end;
  }
  footer div {
    padding: 1rem;
  }
</style>

 

przykładowy wygenerowany kod html

<header class="container">
  <nav class="horizontal">
    <ul>
      <li>
        <a href="https://www.google.com">Google</a>                        
      </li>
      <li>
        <a href="https://www.facebook.com">Facebook</a>                       
      </li>
      <li>
        <a href="https://www.twitter.com">Twitter</a>
      </li>
      <li>
        <a href="https://www.github.com">GitHub</a>        
      </li>
      <li>
        <a href="https://www.linkedin.com">LinkedIn</a>          
      </li>          
    </ul>          
  </nav>
</header>
<main class="container">
  <div class="content">
    Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor
  </div>
</main>
<footer class="container">
  <div class>STOPKA</div>
</footer>

komentarz 28 sierpnia 2023 przez juuunior Początkujący (460 p.)

Gdy uda mi się przyswoić Wasze propozycję to postaram się napisać jakiś większy projekt obiektowo . Ciekawi mnie jeszcze funkcja autoload  w dużych projektach zapewne klasy są w różnych folderach każda w innym pliku , AI podpowiada mi taki kod na podpinanie

  function autoload($className) {
        $directory = array('', 'classes/', 'model/', 'logic/');
        $fileFormat = array('%s.php', '%s.class.php');
        foreach ($directory as $current_dir) {
            foreach ($fileFormat as $current_format) {
                $path = $current_dir.sprintf($current_format, strtolower($className));
                if (is_file($path)) {
                    include_once $path;
                    return;
               }
            }
        }
    }
    spl_autoload_register('autoload');

zobaczę czy zadziała...    w dokumentacji do podpinania z jednego folderu jest tak

  spl_autoload_register(function ($class_name) {
        include("model/". $class_name . '.php');
    });

 

Podobne pytania

+4 głosów
4 odpowiedzi 608 wizyt
pytanie zadane 10 kwietnia 2015 w PHP przez HaKIM Szeryf (87,590 p.)
+2 głosów
2 odpowiedzi 315 wizyt
pytanie zadane 11 kwietnia 2015 w PHP przez HaKIM Szeryf (87,590 p.)
0 głosów
1 odpowiedź 493 wizyt
pytanie zadane 11 grudnia 2019 w C i C++ przez enero Początkujący (330 p.)

93,013 zapytań

141,977 odpowiedzi

321,266 komentarzy

62,355 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Wprowadzenie do ITsec, tom 2

Można już zamawiać tom 2 książki "Wprowadzenie do bezpieczeństwa IT" - będzie to około 650 stron wiedzy o ITsec (17 rozdziałów, 14 autorów, kolorowy druk).

Planowana premiera: 30.09.2024, zaś planowana wysyłka nastąpi w drugim tygodniu października 2024.

Warto preorderować, tym bardziej, iż mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy dodatkowe 15% zniżki! Dziękujemy zaprzyjaźnionej ekipie Sekuraka za kod dla naszej Społeczności!

...