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

Zrozumieć obiektowość

Object Storage Arubacloud
+1 głos
237 wizyt
pytanie zadane 25 sierpnia 2023 w PHP przez juuunior Początkujący (300 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 (86,400 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 (25,930 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 (253,420 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 (300 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 482 wizyt
pytanie zadane 10 kwietnia 2015 w PHP przez HaKIM Szeryf (87,590 p.)
+2 głosów
2 odpowiedzi 292 wizyt
pytanie zadane 11 kwietnia 2015 w PHP przez HaKIM Szeryf (87,590 p.)
0 głosów
1 odpowiedź 388 wizyt
pytanie zadane 11 grudnia 2019 w C i C++ przez enero Początkujący (330 p.)

92,579 zapytań

141,432 odpowiedzi

319,664 komentarzy

61,964 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...