Composer to dzisiaj bez wątpienia podstawa każdego projektu w PHP. Dzięki Composerowi nie tylko dodamy interesujące nas biblioteki, ale też m.in. zarządzimy przestrzeniami nazw (ang. namespace). Dodatkowo Composer wczytuje za nas (ang. autoload) wszystkie plików PHP w naszym projekcie. Żeby to lepiej zrozumieć, stwórzmy prosty projekt.
Nowy projekt w Composer
Naszym prostym projektem będzie wyświetlanie kursu walut. Zaczniemy zatem wchodząc do pustego folderu projektu i wpisując komendę:composer init
Zostaniemy spytani najpierw o Package name. Z założenia używa się nazwy w formacie „<vendor>/<name>”, co oznacza, że jeśli np. publikujemy kod na GitHub, to <vendor> będzie nazwa użytkownika lub organizacji (w moim przypadku luklewluk), a <name> to po prostu będzie nazwa repozytorium, dowolna pasująca do projektu czyli na przykład „exchange”. Czyli pełna nazwa: luklewluk/exchange .
Żeby nie utrudniać sobie na początek, to każde kolejne pytanie możemy na razie pominąć, zwłaszcza, że nie będzie to projekt publiczny 😄
Pytanie, którego nie chcemy pominąć to pytanie odnośnie PSR-4:
Add PSR-4 autoload mapping? Maps namespace „Luklewluk\Exchange” to the entered relative path. [src/, n to skip]:.
Naciskamy Enter, gdyż chcemy dodać PSR-4 autoload. Później wyjaśnię dlaczego.
Po tej operacji, powinniśmy mieć wygenerowany plik „composer.json” oraz folder „vendor”. Następnie tworzymy plik PHP przez który wystartujemy projekt. Nazwijmy go „run.php”. Teraz zgodnie z podpowiedzią którą otrzymaliśmy na koniec, powinniśmy „zaincludować” autoloader Composera w naszym projekcie dodając:require 'vendor/autoload.php';
Dodawanie bibliotek do projektu
Tak jak założyliśmy, nasza aplikacja powinna pokazywać nam kurs walut, np. ile PLN musimy zapłacić za 1 EUR. Najprościej możemy to rozwiązać znajdując interesującą nas bibliotekę i dodając ją do naszego projektu. Żeby znaleźć bibliotekę można wejść na stronę repozytorium paczek dla PHP czyli Packagist i użyć tamtejszej wyszukiwarki. Dla uproszczenia niech to będzie kurs NBP, gdyż dostęp do ich API jest publiczny, bez wymogu rejestracji. W wyszukiwarce Packagista wpisuję więc „nbp”:
Najpopularniejsza obecnie biblioteka to maciej-sz/nbp-php. Żeby ją dodać do naszego projektu wpisujemy komendę:composer require maciej-sz/nbp-php
Gdy biblioteka została prawidłowo dodana, to możemy zacząć z niej korzystać. Gdy korzystamy z zewnętrznych bibliotek, należy korzystać z ich dokumentacji, gdyż wtedy dowiemy się, jak możemy daną bibliotekę zaimplementować w naszym kodzie. W naszym przypadku dodajemy do naszego pliku run.php następujące linie:
$nbp = new \MaciejSz\NbpPhp\NbpRepository();
$currencyData = $nbp->getRate('2023-01-25', 'EUR');
echo $currencyData->avg;
Powyższym kodem sprawdzamy średni kurs NBP dla Euro, z dnia 25 stycznia 2023. Po uruchomieniu naszego skryptu powinniśmy zobaczyć wartość 4.7079:
Tworzenie klas
Mamy już działający kod, używający zewnętrznej biblioteki. Można więc w tym miejscu skończyć wpis, ale jeśli dobrze pamiętacie, to przy tworzeniu projektu przez komendę composer init, na końcu poprosiliśmy o stworzenie dla nas „autoloadera PSR-4”. Dzięki temu, do naszego composer.json zostały dodane następujące linie:
"autoload": {
"psr-4": {
"Luklewluk\\Exchange\\": "src/"
}
},
Przeanalizujemy je po kolei:
1) Autoload – ustawienie, że są pliki PHP w naszym projekcie, które byśmy chcieli „includować”
2) PSR-4 – to metoda jaką użyje Composer do autoloadingu. Można więcej poczytać o niej tutaj
3) „Luklewluk\\Exchange\\” – oznacza, że Composer zarezerwował namespace dla moich klas w PHP
4) „src/” – to nic innego jak folder, w którym będą znajdować się pliki projektu
Wiem że obecnie może nie być to zbyt jasne, dlatego przejdźmy od razu do praktyki 😄
Zacznijmy od stworzenia folderu „src”, a w tym projekcie stwórzmy klasę Rate. Prawidłowy plik src/Rate.php
będzie wyglądać tak:
<?php
namespace Luklewluk\Exchange;
class Rate
{
}
Do tej pustej klasy dodajmy metodę „getEurRate”, której zadaniem będzie zwracać nam kurs Euro. Metoda jako argument niech przyjmuje datę w formacie string oraz niech zwraca wartość kursu też w jako string.
Przenosząc wcześniejszą logikę z pliku run.php, nasza klasa będzie wyglądać tak:
<?php
namespace Luklewluk\Exchange;
use MaciejSz\NbpPhp\NbpRepository;
class Rate
{
public function getEurRate(string $date): string
{
$nbp = new NbpRepository();
$currencyData = $nbp->getRate($date, 'EUR');
return $currencyData->avg;
}
}
Klasa Rate jest już ukończona i gotowa do używania.
Ważna uwaga: Tak na prawdę, powinniśmy tutaj zastosować DI (Dependency Injection), czyli obiekt NbpRepository powinien być „wstrzyknięty” w konstruktorze klasy. Zrobiłem więc małe uproszczenie, gdyż temat DI poruszę głębiej w jednym z kolejnych wpisów.
Wracamy do naszego pliku run.php, zmieniamy go by odwoływał się jedynie do naszej klasy, którą właśnie utworzyliśmy:
<?php
require_once 'vendor/autoload.php';
$rate = new \Luklewluk\Exchange\Rate();
echo $rate->getEurRate('2023-01-26');
Zmieniłem dodatkowo datę odczytu kursu z 25 na 26 stycznia, by wynik nieco różnił się od poprzedniego. Kod uruchamiamy tak samo jak wcześniej, czyli używając „php run.php”.
Podsumowanie
Tematy poruszone w tym wpisie są absolutnym fundamentem w tworzeniu aplikacji w PHP. Jeśli zaczynacie pracę z dowolnym frameworkiem, projekt praktycznie zawsze będzie korzystać z Composera. Jest to ogromne ułatwienie, gdyż jak widzicie, napisaliśmy działającą i użyteczną aplikację, pisząc minimalną ilość kodu.
Jeśli chodzi o kwestie związane z klasami, to obecna praktyka w PHP nakazuje pisać jedynie obiektowo (pomijamy tu wyjątki od reguły typu WordPress). Możesz też zauważyć, że Composer w pewien sposób też narzuca OOP (Object-Oriented Programming). Zaznaczę tutaj, że rozpoczynając przygodę z innymi językami np. Java lub C#, również od razu zostaniemy wrzucani na głęboką wodę, czyli pisanie kodu w klasach. Dlatego im wcześniej zaczniecie korzystać z obiektów, tym lepiej dla Was 💪