Czy kod php jest poprawny ?

Czy kod php jest poprawny ?
V2
  • Rejestracja:około 4 lata
  • Ostatnio:3 miesiące
  • Postów:86
0

Cześć, czy mógłby ktoś ocenić czy mój kod php jest, poprawny ? Oczywiście poniższy kod działa tak jak tego oczekuje, ale po prostu chce się dowiedzieć czy poprawnie programuje, czy coś mógłbym lepiej zrobić, inaczej zmienne ponazywać itp. Z góry dzięki.

klasa odpowiedzialna za walidację awatara

Kopiuj
class AvatarValidation
{
    private $data;
    private $database;
    private $error = '';


    public function __construct($database, $data)
    {
        $this->database = $database;
        $this->data = $data;
    }

    public function getError()
    {
        return $this->error;
    }

    public function ValidateAvatar()
    {


        $array_extension = array("jpg", "png", "jpeg");
        $val = htmlspecialchars($this->data['avatar']);
        $ext = pathinfo($val, PATHINFO_EXTENSION);

        if(empty($val))
        {
            return $this->error = "Wybierz zdjęcie";
        }
        else if(! in_array($ext, $array_extension) && !(empty($val)))
        {
            return $this->error = "Nieprawidłowe rozszerzenie pliku";
        }

    }
}

?>

klasa odpowiedzialna za dodawanie zdjęcia

Kopiuj

class PhotoAdding
{
    private $database;
    private $data;
    private $PhotoValidation;

    public function  __construct($database, $data,  $PhotoValidation)
    {
        $this->database = $database;
        $this->data = $data;
        $this->PhotoValidation = $PhotoValidation;
    }

    public function AddPhoto()
    {
        if(empty($this->PhotoValidation->getError()))
        {
            $id = htmlspecialchars($_SESSION['user_id']);
            $photo = htmlspecialchars($this->data['photo']);
            $date = date('Y-m-d');


            $query = $this->database->ConnectDatabase()->prepare("INSERT INTO photo (`user_id`, `photo`, `date_to_add`) VALUES ((SELECT user_id from user where user_id = :id), :photo, :date)");
            $query->bindParam(':id', $id, PDO::PARAM_INT);
            $query->bindParam(':photo', $photo, PDO::PARAM_STR);
            $query->bindParam(':date', $date, PDO::PARAM_STR);
            $query->execute();
        }
    }
}

edytowany 1x, ostatnio: cerrato
LU
  • Rejestracja:około 15 lat
  • Ostatnio:6 miesięcy
1

Programujesz stanowo w AvatarValidation. Widać to w tym że przypisujesz sobie do aktualnego obiektu jakiś error i dajesz mu $data który powinien być parameterem w funkcji AddPhoto.

Dla przykładu metodę ValidateAvatar zmieniłbym tak, że zwraca jakąś inną klasę Error zamiast zapisywać sobie wewnętrznie errora i pobierać go przez getError()
Druga rzecz to niby zwracasz string jako error, ale potem reagowanie na taki błąd musiałoby polegać na porównywaniu stringów zamiast matchowaniu poprzez instanceof.

PhotoAdding -> tutaj dokładnie to samo. W porządku jest to że odwracasz zależności w konstruktorze ale jednocześnie to $data nie pasuje. Obiekt przestaje być re-używalny bo musisz stworzyć kolejny żeby dodać nowe foto. Gdybyś tylko dał $data do AddPhoto() byłoby prościej.

PS. if(empty($this->PhotoValidation->getError())) jak to działa? Skąd PhotoValidation ma info o photo?

EDIT.
Okej, chyba już rozumiem. $data jest w PhotoAdding i AvatarValidation, pewnie to są te same zmienne.

edytowany 5x, ostatnio: Lucassith
serek
  • Rejestracja:około 11 lat
  • Ostatnio:36 minut
  • Postów:1475
2

Tak na szybko:

  1. Brak typowania
  2. Użyj short array syntax
  3. Różny sposób nazywania zmiennych/metod, powinno być cośTam
  4. Nie wrzucaj masy kodu to środka ifa, niepotrzebny dodatkowy nesting level. Spokojnie może obrócić warunek, a resztę kodu dać po zamknięciu ifa, np.:
Kopiuj
if(!empty($this->PhotoValidation->getError())) {
   return;
}
...
  1. Nie sprawdzasz, czy rzeczywiście dodałeś zdjęcie, przydałoby się zwracanie boola - true jeśli dodałeś, a jeśli nie to false. Może też jakiś try/catch warto by dodać.
  2. return $this->error = "Wybierz zdjęcie"; - to jakiś potworek. Skoro masz this i potem getError(), to może lepiej zwracać tylko bool?
  3. Zamiast jednolinijkowego if-else możesz użyć ? :
edytowany 4x, ostatnio: serek
masterc
  • Rejestracja:około 4 lata
  • Ostatnio:ponad 3 lata
  • Postów:425
1

Kod do śmieci, klasa class PhotoAdding łączy sie z baza dancyh xD


Wymyśliłem, że nie chce mi się.
V2
Czemu do smieci ? Przecież tklasa PhotoAdding dodaje zdjęcia do bazy danych
masterc
No bo klasa ma robic jedna rzecz. Ma dodwac zdjecia,a twoja co robi ? Odbira zdjecie, waliduje formularz, i jeszcze na domiar zlego laczy sie z baza. Jestes ponizej juniora , nawet ponizej stazu. Bym ci podziekowal po takim czyms, nawet na staz sie nie nadajesz. Powinien byc plik klasy np photoController.php w nim powinno byc rozszerzenie do klasy ktora laczy sie z baza danych gdzie masz ogolny dostep do DB. Powinna byc klasa validate.php, i photo.php I FORM idzie do kontrolera, on wysyla pola do validate i po zwrotce jesli nie ma bledow idzie do add photo.
MP
U nas też takiego zarozumiałego buraka jak Ty byśmy nie przyjęli :) a jakbyśmy się dowiedizeli ze programujesz w php to jeszcze wyśmiali. Trochę szacunku dla ludzi, nie masz nic do powiedzenia to lepiej siedź cicho. Chcesz się wyżyć, wystartuj do kogoś mocniejszego, bo tak to pokazujesz że jesteś tchórzliwą ciotką i tyle.
O2
  • Rejestracja:około 4 lata
  • Ostatnio:dzień
  • Postów:508
1

@veks21 jak chcesz się nauczyć poprawnie programować to naucz się Laravela i dobrych praktyk, tam jest rozwiązana walidacja i operacje na bazie w elegancki sposób, robienie tego od zera jest bez sensu.
Warto wiedzieć jak działa pdo, ale tak czy siak praca z Eloquentem to zupełnie inny pułap.


sprawiedliwość do sprawiedliwości społecznej ma się tak jak krzesło do krzesła elektrycznego.
66
poprawne programowanie i laravel xd
O2
a co może symfony?
serek
masz coś do symfony?
O2
wolę Laravela.
O2
Z resztą nie istotne, niech się nauczy jakiegokolwiek frameworka, chociaż Ja polecam Laravela.
66
tak, symfony
O2
tsss, niczym nie przewyższa Laravela, Laravel korzysta z Symfony, ale szybciej i zgrabniej się w nim pisze, a eloquent zjada doctrine.
HA
Laravel to jest jeden wielki antypatern i ogólnie robienie sobie żartów z OOP. Porównując implementację active record jakim jest eloquent (kolejny antypatern) do jedynego chyba prawdziwego ORM w PHP zrobiłeś mi dzień. Laravel nadaje się do szybkiego pisania crudów, ale trudno mówić tam o dobrych praktykach.
66
@omenomn2: temat tyczy się poprawności, a nie porównywania do siebie frameworkow, więc trochę zboczyłeś z tematu
O2
Nie Ja się czepiłem Laravela, w mojej wypowiedzi chodziło o to, że pisząc we frameworku można uczyć się jak powinny wyglądać pewne rozwiązania, jak np. walidacja.
O2
@hadwao: widać, że nie wiesz jak działa eloquent i go pewnie nie używałeś nigdy lub robiłeś to nieumiejętnie, bo gdybyś używał to byś wiedział, że jest ok. Laravel ma w sobie mnóstwo wzorców projektowych takich jak iterator (kolekcje), obserwatory modeli, ioc, mvc, singleton, fabryki itd. twierdzenie, że Laravel to antypatern to gruba brednia. Eloquent nie używa przynajmniej anotacji do definiowania parametrów i innych rzeczy tylko normalne tablice w klasie.
HA
@omenomn2: rozumiesz czym jest Active Record? To jest wzorzec polegający na prostym mapowaniu rekordu bazy danych na obiekt. Coś co może być OK w jakiś prostych crudach. W prawdziwych aplikacjach potrzebujesz jednak oderwać persystencję od swojego modelu domenowego bo potrzeba na przykład obsługi dziedziczenia, zagnieżdżania obiektów, używania value objectów itp. i Doctrine robi właśnie to. Zapewne piszesz proste aplikacje będące nakładkami na bazę danych i Eloquent Ci wystarcza + nie rozumiesz co by mogło dać Doctrine.
HA
Co do anotacji to w Doctrine nie są one wymagana - zazwyczaj w aplikacjach używa się osobnych plików XML bo po pierwsze dają więcej możliwości, a po drugie usuwają z modelu informacje o warstwie persystencji. Dla przykładu moje klasy często wyglądają zupełnie inaczej niż to co mam w bazie danych i całość mapowania odbywa się w plikach XML plus dedykowanych mapperach. Dzięki temu pisząc kod nie muszę myśleć o bazie danych. Często piszę kod bez bazy, a dopiero na końcu sobie tworzę odpowiednie tabele i piszę mappery.
HA
Co do Laravela to jest to po prostu opakowanie całej złożoności w proste fasady. Ma to swoje zalety jak na przykład musisz wystawić proste API z autoryzacją, które pod spodem ma prostego CRUDA. Wtedy Laravel oferuje po prostu zrobienie tego prawie automatycznie. Ale jest to kosztem gwałtu na jakości kodu i regułach OOP. Po prostu to jest środowisko do składania aplikacji z klocków. Nie ma w tym nic złego - sam czasami używam jak czas jest ważny, a aplikacja "głupia", ale nie nazywajmy tego dobrymi praktykami.
O2
@hadwao Jeszcze xmla miałbym używać do obsługi bazy danych, świetnie. Widać, że nie wiesz jak działa eloquent i to jest zupełna nieprawda, piszę w Laravelu duże aplikacje i nadaje się do tego bardzo dobrze, jak się umie z niego korzystać, a nie zostało się na wersji 4. Widać, że nie wiesz jak działa ServiceProvider i inne rzeczy w Laravelu, to nie są tylko proste fasady jak Ci się wydaje. Eloquent idealnie wręcz odzwierciedla bazę danych ze wszystkimi realacjami pomiędzy tabelami. Fajnie, że używasz do prostych Crudów, ale może warto się nauczyć pisać w nim
O2
bardziej zaawansowane rzeczy?
HA
Eloquent idealnie wręcz odzwierciedla bazę danych ze wszystkimi realacjami pomiędzy tabelami - widzisz dokładnie o to mi chodzi. Coś co jest ogromną wadą Eloquenta Ty postrzegasz jako zaletę.
O2
Może Ty postrzegasz to jako wadę, a jest to zaletą? Już gadałem z jednym gościem o tym, że on wyrósł z Eloquenta i woli Doctrine, a później się okazało, że nawet nie wie jak działa eager loading i myślał, że na jednym joinie łączy 10 relacji, dlatego takie opinie, że Eloquent jest zły, najpewniej wynikają z niewiedzy o nim, jak się już o tym przekonałem.
serek
myślał, że na jednym joinie łączy 10 relacji - ale to już problem z brakiem podstawowej wiedzy na temat relacyjnych baz danych
serek
Ja się nie znam na Laravelu, ale z Active Record miałem okazję pracować w Yii2. I mam mocno ambiwalentne odczucia. Z plusów to chyba tyle, że model nie był zawalony pierdyliardem linijek z definicjami pól. Z drugiej strony wszystkie wartości pól co mi AR wczytywał z bazy były stringiem, nawet jeśli to był int, mega irytująca rzecz. Pewnie w Laravelu to lepiej działa, ale ja się mocno uprzedziłem do uzywania AR xD
O2
Okej, nie jednym joinem, jednym zapytaniem.
O2
Ale chodzi o to, że nie ogarnia, a krytykuje.
HA
Może Ty postrzegasz to jako wadę, a jest to zaletą? - mówisz, że zaletą jest pisanie kodu biznesowego mocno związanego z bazą danych? WoW. Model w Active Record jest prostą wypadkową struktury bazy danych i to się sprawdza tylko w prostych CRUD'ach (do których zresztą Laravel został stworzony i dlatego tam jest Eloquent, a nie Doctrine). Gdy model biznesowy potrzebuje więcej abstrakcji i musi spełniać sporo reguł biznesowych (czyli nie jest 1:1 zbieżny z bazą danych) to wtedy na scenę wchodzą prawdziwe ORM typu Doctrine.
HA
W PHP brakuje dobrej literatury, ale przeczytaj np. tą książkę: https://leanpub.com/ddd-in-php to zrozumiesz jak używać Doctrine. Zapewne Twoja opinia wynika z tego, że próbujesz Doctrine używać jako Active Record - dać się da, ale to zupełnie bez sensu i wtedy faktycznie lepiej użyć Eloquenta, który jest znacznie prostszy.
O2
Ja w ogóle doctrine nie próbuję używać. Laravel nie został stworzony do prostych crudów, mylisz się.
O2
@hadwao: 50-60 tabel w bazie danych powiązanych ze sobą w różnoraki sposób to jest prosty crud, według Ciebie czy nie? Bo takich gabarytów piszę aplikacje w Laravelu z powodzeniem od ponad 5ciu lat i jakoś nie ma żadnych problemów z abstrakcjami, czy modelem biznesowym.
HA
A jakie znaczenie ma ilość tabel w bazie danych? Ciągle myśląc o aplikacji myślisz w kategoriach warstwy persystencji, czyli typowe myślenie przy pisaniu CRUD. CRUD na 100 tabel nadal pozostaje CRUDEM i Active Record to jest wzorzec stworzony dokładnie do obsługi takich scenariuszy bo sztywno wiążę warstwę persystencji z modelem biznesowym. W ORM typu Doctrine masz te warstwy rozdzielone i np. patrząc na encję biznesową nie wiesz w jaki sposób jest ona zapisywana/odczytywana do bazy, bo może być ona zupełnie dowolnie zmapowana na tabele (lub dokumenty) w bazie.
O2
Przecież jak nie chcesz mieć na sztywno to możesz sobie użyć repozytoriów. Ilość tabel w bazie ma bardzo duże znaczenie, bo im więcej jest tabel i relacji między nimi, tym system jest bardziej złożony to oczywiste. Na dobrą sprawę, każdy system korzystający z bazy danych to crud, ale Ty pisałeś o prostych crudach, a system na 100 tabel to nie jest prosty crud.
HA
@omenomn2: serio zainwestuj te kilka dolarów w książkę, którą Ci podlinkowałem to zrozumiesz o co chodzi. Myśląc o aplikacji ciągle myślisz o bazie danych i dopóki tego nie zmienisz to nie zrozumiesz dlaczego AR jest antywzorcem. Tu masz taki wpis na szybko https://karoldabrowski.com/blog/active-record-pattern-or-anti-pattern-overview/ ale nie sądzę aby zmienił zdanie na jego podstawie. Aby zrozumieć co jest nie tak trzeba wyjść z pewnego stereotypu myślenia o aplikacji.
O2
Tak myślę o bazie danych, bo na bazie danych głównie opierają się wszelkiego rodzaju aplikacje webowe. Ta książka nie jest mi potrzebna, bo Eloquent realizuje bardzo dobrze potrzeby złożonych aplikacji jakie piszę. A baza danych powinna być zaprojektowana również tak, że odzwierciedla potrzeby aplikacji, więc to wszystko jest powiązane, nie projektuje się bazy danych od czapy, żeby później w zupełnie inny sposób pisać kod jakoś w oderwaniu jednego od drugiego.
O2
Dodatkowo powodzenie systemu w dużej mierze zależy od tego jak zaprojektowana jest baza, jak jest zaprojektowana słabo, to później robi się słaby kod, bo np. trzeba operować na relacjach, które nie mają sensu itd.
serek
Dobra, skończcie tą kłótnię xD Skoro @omenomn2 pisze, że póki co AR działa ok i nic więcej mu do szczęścia nie jest potrzebne, to może tak jest.
serek
A jak chcecie dalej kontynuować, to weźcie załóżcie nowy temat, niech każdy się wypowie, co jest wg niego lepsze^^
HA
Ja już nie chcę - wystarczy mi w zupełności świadomość, że @omenomn2 jest szczęśliwy i nie widzi potrzeby zmian.
O2
Bo takiej potrzeby po prostu nie ma.
axelbest
hahaha laravel.....no ja nie moge. Juz wolalbym w Yii pisac czy Zendzie 1.
vpiotr
@axelbest: laravel może i jest słaby ale to 67% rynku wg JetBrains - https://www.jetbrains.com/lp/devecosystem-2021/php/
HA
@vpiotr: Bo niestety 80% rynku PHP to jest amatorka i dlatego takie potworki jak Laravel czy Wordpress mają taki udział w rynku jaki mają. Zobacz na inną statystykę z tego badania - zaledwie 30% osób używa debuggera do debugowania kodu... To doskonale obrazuje jakie aplikacje się pisze w PHP - proste CRUDY w Laravelu debugowane var_dumpem. Jako, że PHP jest bardzo popularne, to nawet te 10-20% fajnych projektów to nadal sporo ilościowo, ale w skali rynku królują proste do bólu technologie.
jurek1980
  • Rejestracja:ponad 8 lat
  • Ostatnio:40 minut
  • Postów:3492
3

Nazwy funkcji masz z wielkiej litery np.$PhotoValidation. Treści komunikatów można np. wynieść do stałych np.

Kopiuj
Class X
{
    private const NO_PHOTO_ERROR =  "Wybierz zdjęcie"
    function check()
    {
       return $this->error = self::NO_PHOTO_ERROR;
    }
}

Masz wtedy wszystkie komunikaty w jednym miejscu i łatwiej czytać kod i edytować treści.
Tu w SQL wyszukujesz Id po otrzynym Id. Wystarczy chyba Insert

Kopiuj
INSERT INTO photo (`user_id`, `photo`, `date_to_add`) VALUES ((SELECT user_id from...)

Reszta już wspomniana.

edytowany 1x, ostatnio: jurek1980
V2
  • Rejestracja:około 4 lata
  • Ostatnio:3 miesiące
  • Postów:86
0

@jurek1980: Ale czy z takim kodem mam szanse dostac prace, ogólnie wszystko działa, tylko pewnie brzydko jest napisany.

cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:mniej niż minuta
  • Lokalizacja:Poznań
  • Postów:8794
2

To zależy kogo szukają. Nas pewno nie jesteś samodzielnym liderem, który dostaje temat i go kompleksowo ogarnie. Ale jeśli będą szukali kogoś na staż, juniora albo ludzika do podszkolenia do prostych zadań to myślę, że masz szansę. Ale od razu mówię - nie nastawiaj się na 15k miesięcznie ;)


V2
No własnie szukam pracy jak junior
jurek1980
  • Rejestracja:ponad 8 lat
  • Ostatnio:40 minut
  • Postów:3492
3
veks21 napisał(a):

@jurek1980: Ale czy z takim kodem mam szanse dostac prace, ogólnie wszystko działa, tylko pewnie brzydko jest napisany.

Szansa jest zawsze. Zrób to nie jako gołe klasy tylko jako działający system. Poczytaj o PSR to pewnie wyjaśni się camelCase i parę wskazanych tu rzeczy. Próbuj i się nie poddawaj.

edytowany 1x, ostatnio: jurek1980
V2
Bo ogolnie to jest tylko kawałek kodu z duzej aplikacji, ktora jest połaczeniem facebooka, twittera i instsgrama i wszystko dziala prawidlowo
serek
  • Rejestracja:około 11 lat
  • Ostatnio:36 minut
  • Postów:1475
1

Szczerze, ja bym miał opory, żeby przyjąć Cię na juniora, prędzej staż. Z drugiej strony, widziałem już gorszy kod juniorów, więc może nie jest tak źle xD Ale po paru linijkach kodu to co najwyżej mogę zgadywać co potrafisz.

W każdym razie mamy 2021 rok, a używasz składni/formatowania jak z czasów PHP 5, a teraz mamy już PHP 8^^ Pierwsze co powinieneś zrobić, to zapoznać się z nowościami. Plus poczytać sobie o linterach do PHP.

jurek1980
Widziałem gorszy kod "seniorów".
serek
No pewnie się da, w każdej próbie seniorów o w miarę dużym rozmiarze N pewnie się trafi choć jeden taki, co nie wiadomo jak się tam znalazł
V2
  • Rejestracja:około 4 lata
  • Ostatnio:3 miesiące
  • Postów:86
0

@serek: Czyli główny problem leży w formatowaniu kodu, ze nieuzywam wersji 8 php, tak ?

jurek1980
Spróbuj użyć strict typing w drugiej wersji tej apki.
serek
  • Rejestracja:około 11 lat
  • Ostatnio:36 minut
  • Postów:1475
1
veks21 napisał(a):

@serek: Czyli główny problem leży w formatowaniu kodu, ze nieuzywam wersji 8 php, tak ?

Nie, ale dużo lepiej to będzie to wyglądać.

V2
  • Rejestracja:około 4 lata
  • Ostatnio:3 miesiące
  • Postów:86
0

@jurek1980:
Zmieniłem troche kod, aby funkcja zwracała określony typ danych.

Kopiuj
class AvatarValidation
{
    private $data;
    private $database;
    private string $error = '';

    public function __construct($database, $data)
    {
        $this->database = $database;
        $this->data = $data;
    }

    public function getError(): string
    {
        return $this->error;
    }

    public function ValidateAvatar(): string
    {

        $array_extension = array("jpg", "png", "jpeg");
        $val = htmlspecialchars($this->data['avatar']);
        $ext = pathinfo($val, PATHINFO_EXTENSION);

        if(empty($val))
        {
            return $this->error = "Wybierz zdjęcie";
        }
        else if(! in_array($ext, $array_extension) && !(empty($val)))
        {
            return $this->error = "Nieprawidłowe rozszerzenie pliku";
        }

    }
}
edytowany 1x, ostatnio: cerrato
HA
Brakuje Ci jeszcze typowania parametrów np. w konstruktorze, oraz typowania pól klasy. Masz też błąd w ValidateAvatar - jeśli żaden z tych warunków nie zostanie spełniony to funkcja zwrócić void (czyli nic), a nie string. Swoją drogą pewnie wyjątki byłyby tu bardziej na miejscu niż zwracanie stringów.
jurek1980
  • Rejestracja:ponad 8 lat
  • Ostatnio:40 minut
  • Postów:3492
2

To teraz na początku pliku daj
declare(strict_types=1); i zobacz co się zaświeci i spróbuj tak kod napisać by IDE nie okazywało błędów a progrma ciągle działa, tylko rób to jako wersja 1.1

serek
  • Rejestracja:około 11 lat
  • Ostatnio:36 minut
  • Postów:1475
1

Dodatkowo jeszcze:

  1. elseif zwykle się pisze to razem
  2. po co && !(empty($val), zbędna redundancja
  3. po negacji nie dawaj spacji, lepiej wygląda !in_array
edytowany 1x, ostatnio: serek
V2
  • Rejestracja:około 4 lata
  • Ostatnio:3 miesiące
  • Postów:86
0

@jurek1980: Teraz w ogóle nie działa

jurek1980
No bo wiele musisz poprawić by działało, ale chodzi o to żebyś się nauczył. Dobre IDE i działaj.
L7
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 4 godziny
  • Postów:433
1

Jak dla mnie to trochę mało tego kodu żeby coś więcej powiedzieć, no bo co my tu mamy:

  • dwie klasy (jedna do walidacji druga do zapisu do bazy)
  • klasa walidująca posiada konstruktor (gdzie przypisywane jest $database, które jest używane... no właśnie... gdzie?)
  • nazwy metod, zmiennych wcale nie przypominają tego co mają robić (metoda getError zwraca error natomiast metoda ValidateAvatar zwraca stringa, który notabene jest tym samym co getError albo nie zwraca NIC :) )
  • o nazewnictwie zmiennych to już pisano wcześniej

Generalnie z tego co pokazałeś to wiesz jak:

  • zrobić klasę
  • napisać do niej kilka metod
  • i... (dopiszcie jak komuś coś jeszcze wpadnie)

Samo stworzenie klasy to jeszcze nie będzie OOP :)

HA
  • Rejestracja:ponad 6 lat
  • Ostatnio:około 19 godzin
  • Postów:1006
3

Odpowiadając na Twoje najważniejsze pytanie "czy dostanę jakąś pracę" - z takim kodem raczej nie masz szans na pracę w żadnej sensownej firmie. Jeśli faktycznie umiesz napisać coś większego co działa i ogarniasz trochę front to zapewne znajdziesz pracę w jakiejś firmie wdrażającej proste CMS'y - tam jest potrzeba na ludzi, którzy ogólnie ogarniają, a jakość kodu jest na ostatnim miejscu.

Jeśli faktycznie umiesz pisać większe aplikacje, które działają (z tego kodu niestety nikt Ci nie oceni), znasz jakiś framework, to jesteś jednak w całkiem dobrej sytuacji. Moim zdaniem o wiele trudniej jest dojść do poziomu "zero" do "ogarniam" niż od poziomu "ogarniam" do "umiem pisać ładny kod". To jest po prostu wtedy tylko kwestia kogoś kto pokaże Ci odpowiednie wzorce i Twojej woli aby je stosować.

Co bym zrobił na Twoim miejscu to po pierwsze zadbał o kod na poziomie statycznym - to co zaprezentowałeś tutaj to jest automatyczna dyskwalifikacja w większości firm ze względu na to co koledzy pisali wyżej - nikt nawet nie będzie analizował Twojej aplikacji dalej. Trochę jakbyś przyszedł ubrany jak bezdomny do banku i poprosił o usługę private banking - może i masz milion dolarów, ale wyglądasz jak bezdomny więc Cię ochrona wyprosi zanim dotrzesz do odpowiedniej osoby.

Dlatego:

  • tak jak pisał @jurek1980 używaj strict types + typowania wszystkich pól klas, parametrów metod i zwracanych typów - kod Ci przestał działać? To bardzo dobrze - znaczy, ze wychwyciłeś błąd, który mógłby przysporzyć sporo kłopotów na produkcji
  • zainteresuj się PHP8 - @serek tutaj trafnie zauważył, że Twój kod wygląda jakbyś się uczył programowania z książek do PHP5 - miałem identyczne skojrzaenie
  • zainteresuj się tym: https://phptherightway.com/#code_style_guide - to są szalenie ważne rzeczy w komercyjnym kodzie i dzięki temu Twój kod przestanie wyglądać jak bezdomny (przynajmniej na poziomie edycyjnym)
  • jak to ogarniesz to polecam książkę "Czysty kod" - całej zapewne nie zrozumiesz, ale pierwsze kilka rozdziałów to jest dokładnie to czego potrzebujesz

Dalej jak już poprawisz swój kod od strony wizualnej to pora poprawić jego organizację. Tutaj niestety są to lata pracy i ciągle będziesz widział coś do poprawy. Zacząłbym od:

  • nauczenia się phpUnit i rozpoczęcia pisania testów jednostkowych
  • przeczytania jakiejś książki lub obejrzenia jakiegoś dobrego tutoriala o MVC - coś bez frameworka, żeby załapać jak to działa od środka
  • potem próbowałbym masterować jakiś framework typu Symfony + czytał sporo o kodzie, architekturze itp.
  • po 5-10 latach poczujesz się dość komfortowo ;p
Zobacz pozostały 1 komentarz
HA
Małymi kroczkami do celu - nikt nie pisał sam z siebie od razu pięknego kodu. Wiesz już nad czym pracować, więc postaraj się trochę poprawić i wrzucić coś za jakiś czas na forum, żeby zobaczyć czy idziesz w dobrym kierunku.
masterc
"Tak, jak napisałem, stworzyłem dużą aplikację bardzo podobną do facebooka, " o kurła ahahahahahaha ty to umiesz rozbawic :) jasne, juz widze twoja aplikacje gdzie wklasie SendMessage laczysz sie z baza danych zeby wstawic wiadomosc. a maile pewnie wysylasz po wcisnieciu guzika zamiast do kolejki odsylac hahahah xDDDD chyba zes se sam napisal jakis makaron. Pokaz kilka klas z tego twojego fb :)
V2
Tobie na pewno nie nic nie pokaże, bo po pierwsze potrafisz się się tylko z kogoś smiać, i pokazywać jaki to ty jesteś dobry a inni to idioci bo linijki kodu nie potrafią napisać, dopiero chcę dostać pracę jako junior, nie jestem przecież seniorem który będzie pisał czytelny kod i wszystko umiał
teofrast
@veks21: mozliwe ze napisales wielki i czytelny program i chwala Tobie za to ale @masterc wiele lat programuje i duzo lepiej zna sie na tym fachu - a programowanie to trudna rzecz - im wiecej wiem tym wiecej sie dowiaduje ilu rzeczy jeszcze nie umiem
masterc
nie msuisz pokazywac, wyobrazam go sobie, ale zycie jest brutalne jak dobrze wiesz. Tak jak wszyscy ci mowia: Po co robic kolo na nowo? znajdz framework, Symphiny, Zend (Laminas) , Laravel , nabierzesz w miare dobrych nawykow, poznasz eloquenta. Cos umiesz wiec po 2 tygodniach zobaczysz ze zyskasz na tym tylko. Bo tak to zanim ty napiszesz funkjce logowania to ja juz skoncze caly serwis i to prawdopodbnie tylko z listy polecen w treminalu xD Nikt nie zyczy ci zle tylko mowimy jak jest.
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:minuta
  • Lokalizacja:Laska, z Polski
  • Postów:10073
2
veks21 napisał(a):

Tak, jak napisałem, stworzyłem dużą aplikację bardzo podobną do facebooka, która działa, wiec umiem coś większego napisać, dużo gorzej jest tylko z czytelnością kodu, będe próbwać jakoiś poprawić ten kod, ale juz widze ze nie będze to łatwe zmieniać, szkoda ze nie stosowałem takich praktyk jak pisałem aplikacje

Najlepiej pokaż kod tej aplikacji, to Ci powiemy jak możesz poprawić jej czytelność.

PS: Masz testy do niej?

edytowany 1x, ostatnio: Riddle
V2
Kod wstawie wieczorem, bo teraz piszę z telefonu, i nie robiłem testów do niej
Riddle
@veks21: To bardzo źle. Jak wrzucisz kod to pokażę Ci jak napisać jeden albo dwa początkowe. Potem będziesz musiał pisać sam, jeśli chcesz znaleźć jakąś pracę dobrą.
Riddle
@veks21: to wrzucasz coś?
V2
  • Rejestracja:około 4 lata
  • Ostatnio:3 miesiące
  • Postów:86
0

@TomRiddle:
Poprawiłem trochę te dwie klasy, mam tylko problem jaki typ ma zwracać funkcja validateAvatar, bo ona zwraca zarówno stringa jak i void, a nie mogę dać uni tych dwóch typów, wiec nie wiem, pewnie bede musiał jakoś poważniej tą walidacje zmodyfikować.

Kopiuj
<?php

declare(strict_types=1);

class PhotoAdding
{

    public function  __construct(
        private $database,
        private  array $data,
        private  $PhotoValidation,
    ){}

    public function AddPhoto(): void
    {
        $id = htmlspecialchars($_SESSION['user_id']);
        $photo = htmlspecialchars($this->data['photo']);
        $date = date('Y-m-d');

        if(empty($this->PhotoValidation->getError()))
        {
            $query = $this->database->ConnectDatabase()->prepare("INSERT INTO photo (`user_id`, `photo`, `date_to_add`) VALUES ((SELECT user_id from user where user_id = :id), :photo, :date)");
            $query->bindParam(':id', $id, PDO::PARAM_INT);
            $query->bindParam(':photo', $photo, PDO::PARAM_STR);
            $query->bindParam(':date', $date, PDO::PARAM_STR);
            $query->execute();
        }
    }
}
?>
Kopiuj
<?php

declare(strict_types=1);

class AvatarValidation
{
    private string $error = '';

    public function __construct(
        private  $database,
        private array $data,
    ){}

    public function getError(): string
    {
        return $this->error;
    }

    public function ValidateAvatar()
    {
        $array_extension = array("jpg", "png", "jpeg");
        $val = htmlspecialchars($this->data['avatar']);
        $ext = pathinfo($val, PATHINFO_EXTENSION);

        if(empty($val))
        {
            return $this->error = "Wybierz zdjęcie";
        }
        elseif(!in_array($ext, $array_extension) && !(empty($val)))
        {
            return $this->error = "Nieprawidłowe rozszerzenie pliku";
        }

    }
}

?>
edytowany 2x, ostatnio: cerrato
jurek1980
  • Rejestracja:ponad 8 lat
  • Ostatnio:40 minut
  • Postów:3492
3

Ciągle masz nazwy funkcji z wielkiej litery.
Odnośnie pytania, jeśli błędy wpisuejez w pole klasy, to nie ma sensu chyba zwracać też ich wartości? Mi zawsze walidacja kojarzy się z bool i true dla ok, false dla błędu.
Natomiast wyświetlenie błędów możesz zrobić już po walidacji, jeśli ona nie przejdzie prawidłowo.
BTW metoda jest publiczna. Przydałoby się ją przetestować. W przypadku bool łatwo napiszesz unit testy.

edytowany 3x, ostatnio: jurek1980
V2
  • Rejestracja:około 4 lata
  • Ostatnio:3 miesiące
  • Postów:86
0

@jurek1980:

Czy o taką walidację Ci chodziło ?

Kopiuj
class AvatarValidation
{

    private string $error = '';

    public function __construct(
        private  $database,
        private array $data,
    ){}

    public function getError(): string
    {
        return $this->error;
    }

    public function ValidateAvatar(): bool
    {
        $array_extension = array("jpg", "png", "jpeg");
        $val = htmlspecialchars($this->data['avatar']);
        $ext = pathinfo($val, PATHINFO_EXTENSION);

        if(empty($val))
        {
            return false;
        }
        elseif(!in_array($ext, $array_extension) && !(empty($val)))
        {
            return false;
        }else
            return true;;

    }
}
edytowany 1x, ostatnio: cerrato
jurek1980
  • Rejestracja:ponad 8 lat
  • Ostatnio:40 minut
  • Postów:3492
2

Bliżej. Tylko pozbyleś się tych informacji o błędach. Może dać je do jakichś podmetod? Zastanów się.
Popatrz też na drugi warunek. Sprawdzasz czy val jest empty, a zrobiłeś to już wcześniej i dałeś return.

Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:minuta
  • Lokalizacja:Laska, z Polski
  • Postów:10073
1
veks21 napisał(a):

Poprawiłem trochę te dwie klasy, mam tylko problem jaki typ ma zwracać funkcja validateAvatar(), bo ona zwraca zarówno stringa jak i void, a nie mogę dać unii tych dwóch typów, wiec nie wiem, pewnie bede musiał jakoś poważniej tą walidacje zmodyfikować.

Tragedia.

  • Po pierwsze, to funkcja nie zwraca nigdy void, co najwyżej zwraca null.
  • Po drugie, pomyślałeś może kiedyś czemu nie ma unii typów? Dlatego że taki design jest bardzo słaby. Idealnie funkcja powinna albo zawsze zwracać string albo zawsze nic.
  • Po trzecie, NIGDY ale to nigdy, nie łącz HTMLa z SQL. To że robisz htmlspecialchars() zanim wsadzisz do bazy danych to w najlepszym wypadku recepta na bugi, w najgorszym niesamowite narażenie się na luki w bezpieczeństwie. Nigdy nie rób htmlspecialchars() przed wkładaniem danych do bazy; zrób to dopiero przy wyświetlaniu tych danych, i to tylko jeśli pokazujesz je w HTML.

Co do kodu samego, to pytanie czy używasz tego getError() jeszcze w innym miejscu? Czy tylko w tym kodzie którym pokazałeś? Jeśli używasz go gdzieś indziej, to wklej również ten kod.

jurek1980
  • Rejestracja:ponad 8 lat
  • Ostatnio:40 minut
  • Postów:3492
1

@TomRiddle:

Idealnie funkcja powinna albo zawsze zwracać string albo zawsze nic.

Zbyt duże uogólnienie. Ktoś tak jeszcze pomyśli. Poza tym rozszerz swój pogląd, dlaczego funkcja walidujaca powinna według Ciebie zwracać Void?

HA
Funkcje walidujące to grząski temat - co programista to opinia ;p Ja osobiście jak piszę własny kod to robi validatory w postaci asercji czyli funkcja void rzucająca wyjątki. Ale w sumie każde podejście ma swoje plusy i minusy.
jurek1980
@hadwao: wiadomo, ale mi bardziej pasuje np. bool niż string, jeśli to metoda klasy walidującej. W podejściu z Void owszem przy wyjątkach, tylko tutaj ich nie mamy. Zaraz zrobi się burza nie powiem czego :)
HA
U mnie klasyfikacja jest taka: void + exception > bool > array > string, ale tak jak pisałem każde podejście ma sens. W przypadku osób początkujących bool jest prostszy do zrozumienia, więc nawet nie pisałem o wyjątkach w moim "CR" poniżej.
HA
  • Rejestracja:ponad 6 lat
  • Ostatnio:około 19 godzin
  • Postów:1006
1

Chłopaki tutaj mówią o architekturze więc ja trochę pochylę się nad samym kodem. Ta klasa ma sporo rzeczy do poprawy. To co musisz zrozumieć, to w kodzie komercyjnym bardzo ważna jest czytelność. Tymczasem Twoja klasa jest bardzo zawiła i nieczytelna + zawiera sporo martwego kodu. Kilka moich spostrzeżeń:

  • nazwa wydaje mi się dziwna - raczej powinno być AvatarValidator
  • nie rozumiem poco tutaj konstruktor / stan w tej klasie. Database nigdzie nie jest używany (i dobrze), a przekazywanie danych w konstruktorze też trochę nie ma sensu. Lepiej przekazać path od razu do funkcji validatora.
  • po co funkcja getError()? Przecież nigdzie w obecnej klasie nie masz tych błędów, więc zawsze będzie zwracany pusty string
  • dlaczego nazwa funkcji z dużej litery? W php konwencja dla nazw funkcji i zmiennych to camelCase
  • tak jak pisałem, wg mnie znacznie ładniej byłoby ścieżkę do pliku przekazać do funkcji, a nie przekazywać tam całą tablicę $data - robisz niepotrzebne zależności. Skoro funkcja potrzebuję tylko ścieżki do pliku to tylko ścieżkę powinna otrzymać. Dzięki temu funkcja jest łatwiejsza do zrozumienia i przetestowania
  • linia pierwsza - ponownie zmienne w php to camelCase. Druga sprawa to dodawanie typu zmiennej w nazwie jest bez sensu. Powinno być raczej coś w stylu $allowedMediaFileExtensions. Używasz w tej linii również przestarzałej konstrukcji array() - obecnie używamy []. Stosujesz też podwójne cudzysłowy - w statycznych stringach powinno się stosować pojedyńcze bo taka jest konwencja + jest to trochę wydajniejsze. Wreszcie czy ta tablica to zmienna? Nie wydaje mi się - to raczej jest stała, więc lepiej to przenieść do stałej. W przyszłości ułatwi to refacoring i będzie bardziej jasne dla programisty
  • linijka kolejna. Musisz zdecydowanie popracować nad nazewnictwem zmiennych. $val, $ext to nie są jednoznaczne zmienne. Nazwa zmiennej powinna przekazywać co w niej jest, bo jak za miesiąc wrócisz to nie będziesz musiał analizować kodu.
  • no i jeszcze ten okropny zapis warunków logicznych...

Po pierwsze powinieneś jak ognia unikać konstrukcji if/else bo bardzo ogranicza ona czytelność kodu. Po drugie w Twoim kodzie elsy zastosowałeś zupełnie zbędznie. Po co elseif skoro jeśli warunek w if jest spełniony to funkcja w tym miejscu się kończy bo jest return?
Zastanów się też nad sensem używania konstrukcji w stylu if $val === true return true else return false - bo dokładnie takiej konstrukcji użyłeś. Przecież wystarczy zrobić return $val

Jeśli dobrze rozumiem koncept Twojej klasy to można by ją zapisać mniej więcej tak:

Kopiuj
<?php

declare(strict_types=1);

class AvatarValidator
{
    private const ALLOWED_MEDIA_FILE_EXTENSIONS = ['jpg', 'png', 'jpeg'];

    public function validate(string $path): bool
    {
        if (!$path) {
            return false;
        }

        return in_array(
            pathinfo($path, PATHINFO_EXTENSION),
            self::ALLOWED_MEDIA_FILE_EXTENSIONS
        );
    }
}

Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:minuta
  • Lokalizacja:Laska, z Polski
  • Postów:10073
0
jurek1980 napisał(a):

@TomRiddle:

Idealnie funkcja powinna albo zawsze zwracać string albo zawsze nic.

Zbyt duże uogólnienie. Ktoś tak jeszcze pomyśli. Poza tym rozszerz swój pogląd, dlaczego funkcja walidujaca powinna według Ciebie zwracać Void?

Ale ja nic takiego nie mówiłem.

Mówiłem że funkcje w ogóle które raz zwracają string a raz null to słaby design.

edytowany 1x, ostatnio: Riddle
HA
Z tym się trudno kłócić. Nullable to było od początku bardzo kontrowersyjne RFC. Moim zdaniem dobrze, że to finalnie dodali, ale faktem jest, że w 99% jest stosowane niepotrzebnie i psuje kod. Podobnie będzie teraz w php 8 z union types jako typ zwracany.
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:minuta
  • Lokalizacja:Laska, z Polski
  • Postów:10073
0
veks21 napisał(a):

Poprawiłem trochę te dwie klasy, mam tylko problem jaki typ ma zwracać funkcja validateAvatar, bo ona zwraca zarówno stringa jak i void, a nie mogę dać uni tych dwóch typów, wiec nie wiem, pewnie bede musiał jakoś poważniej tą walidacje zmodyfikować.

A po czwate w sumie, kolejny błąd, u Ciebie operujesz na tej zmiennej $this->data. To jest zbyt zserializowana dana, powinieneś ją odpakować dużo wcześniej, jak ją tylko dostaniesz. Ja bym widział tak ten kod:

Kopiuj
<?php
class PhotoRepository
{
    public function __construct(private $database)
    {
    }

    public function AddPhoto(int $id, string $photo, string $date): void
    {
        $query = $this->database->ConnectDatabase()->prepare("INSERT INTO photo (`user_id`, `photo`, `date_to_add`) VALUES ((SELECT user_id from user where user_id = :id), :photo, :date)");
        $query->bindParam(':id', $id, PDO::PARAM_INT);
        $query->bindParam(':photo', $photo, PDO::PARAM_STR);
        $query->bindParam(':date', $date, PDO::PARAM_STR);
        $query->execute();
    }
}

class Avatar
{
    public function __construct(private string $avatar)
    {
    }

    public function getAvatar(): string
    {
        if ($this->avatar === '') {
            throw new ValidationException("Wybierz zdjęcie");
        }
        if (!in_array($this->getExtension(), ['jpg', 'png', 'jpeg'])) {
            throw new ValidationException("Nieprawidłowe rozszerzenie pliku");
        }
        return $this->avatar;
    }

    private function getExtension(): string
    {
        return pathinfo($this->avatar, PATHINFO_EXTENSION);
    }
}

class ValidationException extends Exception {}

Użycie

Kopiuj
$avatar = new Avatar($this->data['photo']);
$repository = new PhotoRepository($database);
try {
    $repository->AddPhoto($_SESSION['user_id'], $avatar->getAvatar(), date('Y-m-d'));
}
catch (ValidationException $exception) {
    $errorMessage = $exception->getMessage();
    // pokaż wiadomość userowi
}
edytowany 2x, ostatnio: Riddle
HA
Hmm a dlaczego dajesz walidację w getAvatar? Jeśli avatar jest niepoprawny to IMO obiekt w ogóle nie powinien powstać. Zazwyczaj daję asercje w konstruktorze, żeby exception był możliwie blisko miejsca, gdzie faktycznie jest problem.
Riddle
Wszystko jedno. Można też to dodać do konstruktora, byłoby to bardziej obiektowe podejście, ja pewnie sam bym tak zrobił w swojej aplikacji; ale na forum znajdą się ludzie którym się nie podoba, zwłaszcza jeśli przyjdą z ServiceEverything-landu, więc to dla nich.
V2
  • Rejestracja:około 4 lata
  • Ostatnio:3 miesiące
  • Postów:86
0

@TomRiddle: Tylko ten kod jest niepoprawny, ponieważ tworząc obiekt klasy Avatar powinno być użyte $_POST, a nie $this->data['photo'].

@TomRiddle:
Taki kod działa,poprawnie, trochę jest inny od twojego ale twój pkazywał kilka błedów

Kopiuj
<?php

declare(strict_types=1);

class Avatar
{
    public function __construct(
        private $data,
    ){}
    
    public function getAvatar(): string
    {
        $val = $this->data['avatar'];

        if(empty($val))
        {
            throw new ValidationException("Wybierz zdjęcie");
        }
        else if(!in_array($this->getExtension(), ['jpg', 'png', 'jpeg']))
        {
            throw new ValidationException("Nieprawidłowe rozszerzenie pliku");
        }
        return $val;

    }

    private function getExtension(): string
    {
        $val = $this->data['avatar'];

        return pathinfo($val, PATHINFO_EXTENSION);
    }
}

class ValidationException extends Exception {}
?>
Kopiuj
<?php

declare(strict_types=1);

class AvatarUpdating
{

    public function  __construct(
        private $database,
    ){}

    public function UpdateAvatar(int $id, string $photo): void
    {
            $query = $this->database->ConnectDatabase()->prepare("UPDATE user set avatar = :avatar where user_id = :id");
            $query->bindParam(':avatar', $photo, PDO::PARAM_STR);
            $query->bindParam(':id', $id, PDO::PARAM_INT);
            $query->execute();
    }
}

?>
Kopiuj
$avatarValidation = new Avatar($_POST);
$update_avatar = new AvatarUpdating($database);

<?php
                        if(isset($_POST['submit_avatar']))
                        {
                            try {
                                    $update_avatar->UpdateAvatar($_SESSION['user_id'], $avatarValidation->getAvatar());
                                }catch (ValidationException $exception)
                                {
                                    echo $errorMessage = $exception->getMessage();
                                }
                        }
                        ?>
edytowany 1x, ostatnio: cerrato

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.