Skocz do zawartości

Kurs PHP by PanKrok - Teoria #4 Static, Autoload/Composer, PDO


Pankrok
 Udostępnij

Rekomendowane odpowiedzi

  • Ekspert
Opublikowano
Opublikowano

W poprzedniej cześć kursu zabrakło informacji na temat metod i właściwości statycznych, zaraz to nadrobimy. Dodatkowo zobaczymy jak dynamicznie ładować klasy z innych plików, poznamy przestrzenie nazw i co najważniejsze połączymy się z bazą danych za pomocą PDO. Nie przedłużając:

1. Static - metody i właściwości statyczne.

Ostatnio dowiedziałeś się ze $this dotyczy zawsze klasy w której jesteśmy, nie jest to do końca prawdą. Istnieją przypadki kiedy nie dostaniemy się do wybranej funkcji lub właściwości za pomocą tego słowa. Powiem więcej, tworząc nową instancję naszej klasy też nie dostaniemy się za pomocą strzałki ($foo->bar;) do właściwości statycznej. Aby dobrać się do do naszych statycznych elementów użyjemy nazwy klasy dwukropka razy dwa :: jeśli jesteśmy poza klasą, a w samej klasie słowa self.

<?php declare(strict_types = 1);

Class Foo {
    
    public static int $foo = 1;
    protected static int $bar = 0;
    
    public static function bar(): string
    {
        return sprintf('My foo is: %d and my bar is: %d', self::$foo, self::$bar) . PHP_EOL;
    }
    
    public static function setBar(int $bar): void
    {
        self::$bar = $bar;
    }

}

echo Foo::bar(); // My foo is: 1 and my bar is: 0
echo Foo::$foo . PHP_EOL; // 1

$foo_instance = new Foo();
echo $foo_instance->bar(); // My foo is: 1 and my bar is: 0

Foo::setBar(12);

echo $foo_instance->bar(); // My foo is: 1 and my bar is: 12

Teraz ciekawa sprawa odnośnie statycznych właściwości, ich zmiana spowoduje zmianę wszędzie w naszym kodzie, jak widać po wywołaniu ostatniej linijki.

2. Composer i autoload

Do tej pory wszystko trzymaliśmy w jednym pliku, takie rozwiązanie jest niewygodne i niepraktyczne, czy nie lepiej żeby nasze klasy były w osobnych plikach? Tutaj z pomocą przychodzi autoload, choć w praktyce nie korzysta się z tej funkcji bezpośrednio ale o tym za chwilę. Powiedzmy ze masz swój projekt, jest tam index.php, autoload.php i folder app  w którym trzymasz swoje klasy Auth i Page do zarządzania stronami i logowaniem, niby można użyć include do załadowania dodatkowego pliku, ale co jeśli projekt się rozrośnie i tych plików będzie 50? Totalna masakra, na szczęście możemy załadować nasze klasy z pomocą funkcji spl_autoload_register w pliku autoload.php:

<?php
spl_autoload_register(function ($class_name) {
    include __DIR__ . '/app/' . $class_name . '.php';
});

W rzeczywistości nie korzysta się bezpośrednio z tej funkcji a z programu composer, który generuje autoload na podstawie pliku composer.json (może robić o wiele więcej ale o tym później). Dodatkowo pozwala nam na łatwe korzystanie z przestrzeni nazw. Przestrzeń nazw to nic innego jak informowanie o "prefixie" jaki będzie miała nasza klasa, dzięki temu można mieć zarówno kontroler o klasie User w przestrzeni Controller (w rzeczywistości np App\Controller\User) i model użytkownika User w przestrzeni nazw Model (czyli App\Model\User), zgodnie z wytycznymi PSR każdy z plików jest w odpowiednim folderze i tak kontroler usera będzie w katalogu app/Controller a model app/model

// przykladowa zawartosć pliku composer.json

{
    "name": "pecetowicz/simple-blog",
    "description": "Prosta aplikacja stworzona na potrzebu kursu PHP dla użytkoników pecetowicz.pl",
    "autoload": {
        "psr-4": {
            "App\\": "app"
        }
    }
}


Korzystanie z composera wymaga minimalnej znajomości wiersza poleceń, po utworzeniu w głównym katalogu pliku composer.json i zainstalowaniu composera należy uruchomić konsolę i wykonać polecenie
composer install
zostanie wygenerowany katalog vendor w którym znajdują się wszystkie nasze zależności, w tym wypadku automatyczne ładowanie klas z katalogu app. Aby lepiej zrozumieć działanie w osobnym poście zamieszczę wpis praktyczny, stworzymy prostą aplikację do typu blog, jednak do tego będziemy potrzebowali połączenia z bazą danych.

2. PDO

Ok, wiemy jak możemy przechwytywać dane za pomocą formularzy, teraz musimy gdzieś te dane składować, najłatwiej zrobić to w bazie MySQL. Aby połączyć się z bazą danych możemy skorzystać z PDO lub funkcji mysqli, osobiście wolałem zawsze PDO, wydaje mi się na start bardziej przystępne i przyjemniejsze w użyciu. Połączmy się z naszą bazą danych 🙂

I Łączenie z bazą danych

<?php declare(strict_types = 1);

$host = 'localhost';
$db = 'baza_1';
$user = 'root';
$password = 'MyHardPassword';

$dsn = "mysql:host=$host;dbname=$db;charset=UTF8";

$pdo = new PDO($dsn, $user, $password);
if ($pdo) {
  echo "Connected to the $db database successfully!";
}

jeśli kod wykona się poprawnie zobaczymy informację że połączyliśmy się z naszą bazą danych, teraz pozostaje już tylko utworzyć odpowiednie tabele i wrzucić tam dane. Zacznijmy od tworzenia tabel. Można to zrobić bezpośrednio w PMA, z poziomu konsoli jak również przez kod PHP, tabele najczęściej tworzymy podczas instalacji aplikacji lub podczas jej aktualizacji, stworzymy sobie tabelę news która będzie zawierała pola: id, name, content, autor, created_at, updated_at, jeśli nie miałeś wcześniej styczności z MySQL nie musisz się martwić na początku wystarczy Ci minimalna znajomość zapytań MySQL które zamieszczę tutaj.

II Tworzenie tabli

<?php declare(strict_types = 1);

$dsn = "mysql:host=$host;dbname=$db;charset=UTF8";
$pdo = new PDO($dsn, $user, $password);

$statement = 'CREATE TABLE news( 
        `id`  INT AUTO_INCREMENT,
        `name`  VARCHAR(256) NOT NULL, 
        `content` TEXT NOT NULL, 
        `autor` VARCHAR(100) NOT NULL,
        `created_at` DATETIME NOT NULL,
        `updated_at` DATETIME NOT NULL,
        PRIMARY KEY(id)
    );';
    
$pdo->exec($statement);

Powyższe zapytanie do bazy utworzy odpowiednią tabelę, korzystamy z funkcji exec która wykona nasze zapytanie do bazy danych MySQL, teraz umieśćmy w niej nasze dane:

III Przesyłanie danych

<?php declare(strict_types = 1);

$dsn = "mysql:host=$host;dbname=$db;charset=UTF8";
$pdo = new PDO($dsn, $user, $password);

$sql = 'INSERT INTO news(name, content, autor, created_at, updated_at) VALUES(:name, :content, :autor, :created_at, :updated_at)';

$statement = $pdo->prepare($sql);
$today = date("Y-m-d H:i:s");   

$statement->execute([
    ':name' => 'Nowy wpis',
    ':content' => 'Lorem ipsum...',
    ':autor' => 'PanKrok',
    ':created_at' => $today,
    ':updated_at' => $today,
]);

Dla zmiennej $sql tworzymy string w którym w którym dla tabeli news podajemy jakie kolumny chcemy uzupełnić, i jak oznaczymy wartości poprzedzając je dwukropkiem. Następnie przygotowujemy zapytanie poprzez funkcję prepare do której przesyłamy naszego stringa. Pozostaje już tylko wykonać zapytanie execute przesyłając tablicę z naszymi danymi, jeśli wydaje CI się to skomplikowane spróbuj stworzyć inną tablicę przesłać do niej dane, najłatwiej uczyć się pisząc własny kod.

IV Pobieranie danych

<?php declare(strict_types = 1);

$dsn = "mysql:host=$host;dbname=$db;charset=UTF8";

$pdo = new PDO($dsn, $user, $password);

$sql = 'SELECT id, name, content
		FROM news
        WHERE id = :id';

$id = 1;

$statement = $pdo->prepare($sql);
$statement->bindParam(':id', $id, PDO::PARAM_INT);
$statement->execute();
$data = $statement->fetch(PDO::FETCH_ASSOC);

print_r($data);

Pobieranie danych wygląda bardzo podobnie do ich przesyłania, tak jak wcześniej przygotowujemy zapytanie gdzie zamieszczamy nasz parametr który chcemy przesłać z zewnątrz w tym wypadki :id
Jednak w tym wypadku nie prześlemy go w tablicy, a przypiszemy za pomocą funkcji bindParam(), pełna typów parametrów jest dostępna tutaj PDO PARAMS
po wykonaniu execute pozostaje nam wydobyć dane za pomocą fetch w tym wypadku chcemy je dostać jako tablicę asocjacyjną więc w funkcji prześlemy PDO::FETCH_ASSOC

V Aktualizacja danych

Aktualizacja wygląda bardzo podobnie jak pobieranie danych zmiania się jedynie naszym zapytaniem do bazy danych i brakiem "wydobycia" ich do tablicy:

<?php declare(strict_types = 1);

$dsn = "mysql:host=$host;dbname=$db;charset=UTF8";
$pdo = new PDO($dsn, $user, $password);

$sql = 'UPDATE news
        SET name = :name
        WHERE id = :id';
$name = 'New News Name';
$id = 1;

$statement = $pdo->prepare($sql);
$statement->bindParam(':id', $id, PDO::PARAM_INT);
$statement->bindParam(':name', $name);
$statement->execute();

VI Usuwanie danych

Wszytko jak wyżej, różnica tylko w zapytaniu: $sql = 'DELETE FROM publishers WHERE publisher_id = :publisher_id';

W następnej części przejdziemy do praktyki, napiszemy prosty skrypt do wyświetlania treści (blog) który będzie posiadał panel administracyjny. Wykorzystamy w praktyce wszystkie opisane zagadnienia. Jako że mam teraz sporo spraw na głowie kolejny odcinek kursu za ok 3 tygodnie.

Mam nadzieję ze tym razem o niczym nie zapomniałem @-n3veR i tak pewnie coś znajdzie 😛

Odnośnik do komentarza
Udostępnij na innych stronach

  • Założyciel
Opublikowano
Opublikowano

Dziękuję za kolejną część kursu PHP. Jeżeli chodzi o PDO to zalinkuję do istniejącego już poradnika jako uzupełnienie: Obsługa baz danych za pomocą PDO

Odnośnik do komentarza
Udostępnij na innych stronach

  • Ekspert
Opublikowano
Opublikowano (edytowane)

Nie wiem skąd przekonanie, że mogę się do czegoś przyczepić... 😄

Uwagi:

Pkt 1. Metody statyczne.

Dzięki za przypomnienie w formie kodu jak to działa. W praktyce niewiele korzystam z metod statycznych i część wiedzy wyparowała 😄

 

Pkt 2. Composer.

Pliku `composer.json` nie musimy tworzyć z palca. Wystarczy wejść przez terminal do naszego katalogu projektu i odpalić:

composer init

Po przejściu wszystkich kroków plik utworzy się automatycznie i będziemy mogli odpalić kolejną komendę:

composer install

Wtedy pojawi się dodatkowy plik: `composer.lock` oraz katalog `/vendor/`. I teraz uwaga! Jeżeli pracujemy z GIT-em - systemem kontroli wersji (@Pankrok pewnie wspomni o tym później) - to do GIT trafiają oba pliki composer, ale nie katalog /vendor/ ! Jak pracujecie już z np. Webpackiem, to /vendor/ jest odpowiednikiem /node_modules/ i wiecie o czym piszę 😉

Więcej info w dokumentacji: https://getcomposer.org/doc/ oraz kilku krótkich i darmowych kursach na YT. No i wiaodmo - najpierw trzeba zainstalować samego composera. Albo na swojej maszynie, albo na virtualce, albo w kontenerze. Inaczej będzie problem z odpaleniem polecenia "composer".

 

Muszę jeszcze dorzucić 2 grosze w kwestii przestrzeni nazw. Dotyczą one zarówno danego projektu, ale także i innych projektów. Tutaj trzeba spojrzeć z perspektywy micro i macro. Załóżmy, że mam aplikację i mam w niej taki namespace:

<?php

namespace Foo\Bar\Baz;

Teraz wypuszczam ją na światło dzienne, jako np. Open Source i niech służy community. Ktoś chce skorzystać z mojego projektu jako biblioteka, bo jedna z moich metod, albo i kilka, rozwiązuje u niego pewien problem. Niestety ma identyczną przestrzeń nazw 😕 i powoduje to kilka niedogodnień podczas programowania. Co prawda da się z tym żyć, ale po co? Dlatego przyjęło się, że projekty lokalne, które tworzymy dla siebie / klienta mają namespace zaczynający się z reguły od "App" (ale są też inne 😄), a te projekty, co mają służyć np. jako biblioteki i są dostępne publicznie, zaczynają się zazwyczaj od nazwy projektu / nicku głównego programisty / nazwy firmy.

 

Pkt 3. PDO <--- tutaj trzeba poprawić numerację

PDO tworzy własną abstrakcję na silniku bazodanowym wypuszczając interfejs (metody do wykorzystania po strzałce). Dlatego przy połaczeniu do bazy na początku podajemy jaki silnik chcemy obsłużyć. W naszym przypadku jest to: `mysql:`. Jeżeli teraz chcielibyśmy zmienić silnik na postgresql, sqlite czy mongodb, to nie byłoby z tym większego problemu. Zmieniamy połączenie i poprawiamy składnię zapytań. Używając mysqli() silnie uzależniamy naszą aplikację od jednego silnika. Silne uzależnianie czegoś od czegoś innego nie jest dobrym podejściem w programowaniu.

I taka w sumie mała informacja ode mnie co do samych zapytań. Można robić bindowanie parametrów jako array. Ja jednak preferuję korzystać z metody `bindParam()` tyle razy ile to potrzebne (czyli dla każdego parametru osobno). Mam wtedy większe poczucie "władzy" nad kodem.

 

Do poczytania w wolnej chwili:
- standards: https://www.php-fig.org/psr/
- namespaces: https://www.php.net/manual/en/language.namespaces.php
- PDOhttps://www.php.net/manual/en/book.pdo.php

Edytowane przez -n3veR
Odnośnik do komentarza
Udostępnij na innych stronach

Problem wciąż nierozwiązany? Dodaj swoją odpowiedź

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto. Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się
 Udostępnij

×