Lekcja 30 (OOP 10): Przestrzenie Nazw (Namespaces) i Autoloading (PSR-4)
Witaj w dziesiątej i ostatniej lekcji naszego modułu o Programowaniu Obiektowym i pracy z bazami danych w PHP! W poprzedniej lekcji nauczyliśmy się, jak Cechy (Traits) pozwalają na horyzontalne współdzielenie funkcjonalności między klasami. Dzisiaj zajmiemy się kluczowymi aspektami organizacji kodu w większych projektach PHP: Przestrzeniami Nazw (Namespaces) oraz Automatycznym Ładowaniem Klas (Autoloading), ze szczególnym uwzględnieniem standardu PSR-4.
W miarę rozrastania się aplikacji, liczba klas, interfejsów, cech i funkcji może stać się bardzo duża. Może to prowadzić do konfliktów nazw (dwie różne klasy o tej samej nazwie) oraz do problemów z zarządzaniem zależnościami i dołączaniem plików (require
/include
). Przestrzenie nazw pomagają rozwiązać problem konfliktów nazw, grupując kod w logiczne hierarchie. Autoloading natomiast automatyzuje proces dołączania plików z definicjami klas, gdy są one po raz pierwszy potrzebne, co znacznie upraszcza zarządzanie projektem i poprawia jego wydajność.
Czym Są Przestrzenie Nazw (Namespaces)?
Przestrzeń nazw (Namespace) w PHP to mechanizm pozwalający na enkapsulację (grupowanie) elementów kodu, takich jak klasy, interfejsy, cechy, funkcje i stałe, pod unikalną nazwą. Działa to podobnie do folderów w systemie plików – tak jak możesz mieć plik readme.txt
w wielu różnych folderach, tak możesz mieć klasę User
w wielu różnych przestrzeniach nazw.
Główne cele i korzyści z używania przestrzeni nazw:
- Unikanie konfliktów nazw: To podstawowy cel. Dwie biblioteki lub dwa moduły w twojej aplikacji mogą definiować klasę o tej samej nazwie (np.
Logger
), ale jeśli każda z nich jest w innej przestrzeni nazw (np.MojaFirma\ModulA\Logger
iInnaFirma\Biblioteka\Logger
), nie będzie konfliktu. - Lepsza organizacja kodu: Pozwalają na grupowanie powiązanego kodu, co czyni strukturę projektu bardziej przejrzystą i łatwiejszą do zrozumienia. Nazwy przestrzeni nazw często odzwierciedlają strukturę katalogów projektu.
- Możliwość tworzenia aliasów: Umożliwiają importowanie klas z innych przestrzeni nazw i nadawanie im krótszych aliasów, co poprawia czytelność kodu.
- Współpraca z mechanizmami autoloadingu: Przestrzenie nazw są kluczowe dla nowoczesnych strategii automatycznego ładowania klas, takich jak PSR-4.
Definiowanie Przestrzeni Nazw
Przestrzeń nazw deklaruje się na samym początku pliku PHP (przed jakimkolwiek innym kodem, z wyjątkiem opcjonalnej deklaracji declare(strict_types=1);
) za pomocą słowa kluczowego namespace
.
<?php
// Plik: src/MojaAplikacja/LogikaBiznesowa/Uzytkownik.php
declare(strict_types=1); // Opcjonalne, ale zalecane
namespace MojaAplikacja\LogikaBiznesowa;
class Uzytkownik
{
public string $nazwa;
public function __construct(string $nazwa)
{
$this->nazwa = $nazwa;
echo "Utworzono Uzytkownik z przestrzeni MojaAplikacja\LogikaBiznesowa: " . $this->nazwa . "<br>";
}
}
function pomocniczaFunkcja(): void
{
echo "To jest pomocnicza funkcja z przestrzeni MojaAplikacja\LogikaBiznesowa<br>";
}
const WERSJA_MODULU = "1.0";
// Kod poniżej tej deklaracji należy do przestrzeni MojaAplikacja\LogikaBiznesowa
?>
Nazwy przestrzeni nazw są hierarchiczne i używają odwrotnego ukośnika (\
) jako separatora (podobnie jak w systemach Windows, ale jest to standard w PHP dla namespaces). Konwencją jest używanie nazw w stylu StudlyCaps (CamelCase z wielką literą na początku) dla każdego segmentu przestrzeni nazw.
Jeśli w pliku nie zadeklarowano żadnej przestrzeni nazw, kod należy do globalnej przestrzeni nazw.
Używanie Klas z Przestrzeni Nazw
Aby użyć klasy (lub innego elementu) zdefiniowanej w przestrzeni nazw, musimy odwołać się do niej za pomocą jej pełnej kwalifikowanej nazwy (Fully Qualified Name - FQN), która zawiera całą ścieżkę przestrzeni nazw.
<?php
// Plik: public/index.php (lub inny plik używający klasy Uzytkownik)
require_once __DIR__ .
'/../src/MojaAplikacja/LogikaBiznesowa/Uzytkownik.php
'; // Na razie ręczne dołączanie
// Użycie pełnej kwalifikowanej nazwy
$user1 = new \MojaAplikacja\LogikaBiznesowa\Uzytkownik("Ania");
\MojaAplikacja\LogikaBiznesowa\pomocniczaFunkcja();
echo "Wersja modułu: " . \MojaAplikacja\LogikaBiznesowa\WERSJA_MODULU . "<br>";
// Jeśli jesteśmy w globalnej przestrzeni nazw, początkowy \ jest opcjonalny dla FQN,
// ale jest dobrą praktyką, aby go używać dla jasności.
?>
Importowanie i Aliasowanie (use
)
Ciągłe używanie pełnych kwalifikowanych nazw może być uciążliwe. PHP pozwala na importowanie klas, interfejsów, cech, funkcji (od PHP 5.6) i stałych (od PHP 5.6) z innych przestrzeni nazw za pomocą słowa kluczowego use
. Można również nadać im aliasy.
<?php
// Plik: src/MojaAplikacja/Kontrolery/PanelUzytkownikaKontroler.php
namespace MojaAplikacja\Kontrolery;
// Importowanie klasy Uzytkownik
use MojaAplikacja\LogikaBiznesowa\Uzytkownik;
// Importowanie i aliasowanie klasy Uzytkownik
use MojaAplikacja\LogikaBiznesowa\Uzytkownik as KlientBiznesowy;
// Importowanie funkcji (od PHP 5.6)
use function MojaAplikacja\LogikaBiznesowa\pomocniczaFunkcja;
// Importowanie funkcji i aliasowanie (od PHP 5.6)
use function MojaAplikacja\LogikaBiznesowa\pomocniczaFunkcja as wykonajPomocniczeZadanie;
// Importowanie stałej (od PHP 5.6)
use const MojaAplikacja\LogikaBiznesowa\WERSJA_MODULU;
// Importowanie stałej i aliasowanie (od PHP 5.6)
use const MojaAplikacja\LogikaBiznesowa\WERSJA_MODULU as MODUL_LOGIKI_WERSJA;
class PanelUzytkownikaKontroler
{
public function pokazPanel(): void
{
$user = new Uzytkownik("Kasia"); // Używamy zaimportowanej nazwy
echo "Kontroler używa: " . $user->nazwa . "<br>";
$klient = new KlientBiznesowy("Zosia"); // Używamy aliasu
echo "Kontroler używa klienta (alias): " . $klient->nazwa . "<br>";
pomocniczaFunkcja(); // Wywołanie zaimportowanej funkcji
wykonajPomocniczeZadanie(); // Wywołanie zaimportowanej funkcji pod aliasem
echo "Wersja modułu logiki (zaimportowana stała): " . WERSJA_MODULU . "<br>";
echo "Wersja modułu logiki (alias stałej): " . MODUL_LOGIKI_WERSJA . "<br>";
}
}
// Aby to zadziałało, plik Uzytkownik.php musi być dostępny (np. przez autoloader)
// require_once __DIR__ .
'/../LogikaBiznesowa/Uzytkownik.php
'; // Symulacja dla przykładu
$kontroler = new PanelUzytkownikaKontroler();
$kontroler->pokazPanel();
?>
Deklaracje use
umieszcza się zazwyczaj na początku pliku, po deklaracji namespace
(jeśli istnieje), a przed definicjami klas/interfejsów/itp.
Ważne: use
importuje tylko nazwę, a nie samą klasę. Plik z definicją klasy nadal musi być załadowany (np. przez autoloader lub ręczne require
).
Podprzestrzenie Nazw (Sub-namespaces)
Przestrzenie nazw mogą być zagnieżdżane, tworząc hierarchię, np. MojaFirma\Projekt\Modul\Komponent
. Każdy segment oddzielony \
to kolejny poziom w hierarchii.
Automatyczne Ładowanie Klas (Autoloading)
W małych projektach można ręcznie dołączać pliki z definicjami klas za pomocą require_once
. Jednak w dużych aplikacjach staje się to niepraktyczne i podatne na błędy. Autoloading to mechanizm, który automatycznie ładuje plik z definicją klasy (lub interfejsu/cechy), gdy jest ona po raz pierwszy używana w kodzie.
PHP dostarcza funkcję spl_autoload_register()
, która pozwala zarejestrować jedną lub więcej funkcji (autoloaderów). Gdy kod próbuje użyć nieznanej klasy, PHP wywołuje po kolei zarejestrowane autoloadery, przekazując im nazwę tej klasy. Zadaniem autoloadera jest znalezienie i dołączenie pliku zawierającego definicję tej klasy.
<?php
// Plik: autoload_przyklad.php
spl_autoload_register(function (string $nazwaKlasy) {
echo "Próba załadowania klasy: {$nazwaKlasy}<br>";
// Prosta logika: zamień \ na / i dodaj .php
// Przykład: MojaAplikacja\Logika\Uzytkownik -> MojaAplikacja/Logika/Uzytkownik.php
$sciezkaDoPliku = __DIR__ .
'/src/
' . str_replace("\\", "/", $nazwaKlasy) . ".php";
if (file_exists($sciezkaDoPliku)) {
echo "Znaleziono plik: {$sciezkaDoPliku}, dołączam...<br>";
require_once $sciezkaDoPliku;
} else {
echo "Nie znaleziono pliku dla klasy: {$nazwaKlasy} w {$sciezkaDoPliku}<br>";
}
});
// Załóżmy, że mamy pliki:
// src/MojaAplikacja/Logika/Uzytkownik.php (z klasą Uzytkownik w namespace MojaAplikacja\Logika)
// src/MojaAplikacja/Narzedzia/Logger.php (z klasą Logger w namespace MojaAplikacja\Narzedzia)
// Symulacja istnienia tych plików dla przykładu (normalnie byłyby to osobne pliki)
// if (!class_exists("MojaAplikacja\Logika\Uzytkownik")) { /* ... definicja ... */ }
// Użycie klas spowoduje wywołanie autoloadera
// (Zakładając, że pliki src/MojaAplikacja/Logika/Uzytkownik.php i src/MojaAplikacja/Narzedzia/Logger.php istnieją
// i zawierają odpowiednie klasy w odpowiednich przestrzeniach nazw)
// Dla tego przykładu, stwórzmy tymczasowe pliki:
$srcDir = __DIR__ .
'/src
';
if (!is_dir($srcDir)) mkdir($srcDir, 0777, true);
if (!is_dir($srcDir .
'/MojaAplikacja/Logika
')) mkdir($srcDir .
'/MojaAplikacja/Logika
', 0777, true);
if (!is_dir($srcDir .
'/MojaAplikacja/Narzedzia
')) mkdir($srcDir .
'/MojaAplikacja/Narzedzia
', 0777, true);
file_put_contents($srcDir .
'/MojaAplikacja/Logika/Uzytkownik.php
', "<?php namespace MojaAplikacja\\Logika; class Uzytkownik { public function __construct() { echo 'Uzytkownik z Logika załadowany<br>'; } } ?>");
file_put_contents($srcDir .
'/MojaAplikacja/Narzedzia/Logger.php
', "<?php namespace MojaAplikacja\\Narzedzia; class Logger { public function __construct() { echo 'Logger z Narzedzia załadowany<br>'; } } ?>");
echo "Przed użyciem klas...<br>";
$user = new \MojaAplikacja\Logika\Uzytkownik();
$logger = new \MojaAplikacja\Narzedzia\Logger();
echo "Po użyciu klas.<br>";
// Cleanup tymczasowych plików (dla przykładu)
// unlink($srcDir .
'/MojaAplikacja/Logika/Uzytkownik.php
');
// unlink($srcDir .
'/MojaAplikacja/Narzedzia/Logger.php
');
// rmdir($srcDir .
'/MojaAplikacja/Logika
');
// rmdir($srcDir .
'/MojaAplikacja/Narzedzia
');
// rmdir($srcDir .
'/MojaAplikacja
');
// rmdir($srcDir);
/*
Przykładowy wynik:
Przed użyciem klas...
Próba załadowania klasy: MojaAplikacja\Logika\Uzytkownik
Znaleziono plik: /path/to/script/src/MojaAplikacja/Logika/Uzytkownik.php, dołączam...
Uzytkownik z Logika załadowany
Próba załadowania klasy: MojaAplikacja\Narzedzia\Logger
Znaleziono plik: /path/to/script/src/MojaAplikacja/Narzedzia/Logger.php, dołączam...
Logger z Narzedzia załadowany
Po użyciu klas.
*/
?>
Standard PSR-4 Autoloader
Aby zapewnić interoperacyjność między różnymi bibliotekami i frameworkami PHP, grupa PHP-FIG (PHP Framework Interoperability Group) opracowała standardy rekomendacji (PSR - PHP Standard Recommendation). PSR-4 to standard opisujący, jak autoloadery powinny mapować przestrzenie nazw na ścieżki w systemie plików.
Główne zasady PSR-4:
- Pełna kwalifikowana nazwa klasy (FQN) ma postać:
\<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
. - Podczas ładowania pliku dla FQN, autoloader mapuje prefix przestrzeni nazw na katalog bazowy w systemie plików.
- Część FQN następująca po prefixie przestrzeni nazw (czyli sub-przestrzenie nazw i nazwa klasy) jest mapowana na ścieżkę pliku wewnątrz katalogu bazowego. Separatory
\
w przestrzeni nazw są zamieniane na separatory katalogów (DIRECTORY_SEPARATOR
). - Nazwa pliku musi odpowiadać nazwie klasy (z uwzględnieniem wielkości liter) i mieć rozszerzenie
.php
.
Przykład mapowania PSR-4:
Załóżmy, że mamy następujące mapowanie w naszym autoloaderze:
- Prefix przestrzeni nazw:
MojaFirma\MojaBiblioteka\
- Katalog bazowy:
/var/www/projekt/lib/
Wtedy:
- Klasa
\MojaFirma\MojaBiblioteka\Narzedzia\Kalkulator
będzie szukana w pliku/var/www/projekt/lib/Narzedzia/Kalkulator.php
. - Klasa
\MojaFirma\MojaBiblioteka\Model\Produkt
będzie szukana w pliku/var/www/projekt/lib/Model/Produkt.php
.
Jeśli mamy inny prefix, np.:
- Prefix przestrzeni nazw:
Acme\Log\
- Katalog bazowy:
/var/www/projekt/vendor/acme/log/src/
To klasa \Acme\Log\Writer\File
będzie szukana w /var/www/projekt/vendor/acme/log/src/Writer/File.php
.
Composer i Autoloading PSR-4
Najpopularniejszym narzędziem do zarządzania zależnościami w PHP jest Composer. Composer automatycznie generuje autoloader zgodny z PSR-4 (oraz innymi standardami jak PSR-0, classmap, files) na podstawie konfiguracji w pliku composer.json
.
Przykład fragmentu composer.json
definiującego autoloading PSR-4 dla projektu:
{
"name": "mojafirma/moj-projekt",
"description": "Opis mojego projektu.",
"autoload": {
"psr-4": {
"MojaAplikacja\\": "src/",
"MojaFirma\\Testy\\": "tests/"
}
},
"require": {
"php": ">=8.1"
// ... inne zależności
}
}
W tym przykładzie:
- Wszystkie klasy z przestrzeni nazw zaczynającej się od
MojaAplikacja\
będą szukane w katalogusrc/
(względem katalogu głównego projektu). Np.MojaAplikacja\Kontrolery\DomowyKontroler
będzie wsrc/Kontrolery/DomowyKontroler.php
. - Wszystkie klasy z przestrzeni nazw zaczynającej się od
MojaFirma\Testy\
będą szukane w katalogutests/
. Np.MojaFirma\Testy\Jednostkowe\KalkulatorTest
będzie wtests/Jednostkowe/KalkulatorTest.php
.
Po zdefiniowaniu tego w composer.json
i uruchomieniu composer install
lub composer dump-autoload
, Composer wygeneruje plik vendor/autoload.php
. Wystarczy wtedy dołączyć ten jeden plik na początku aplikacji, aby uzyskać w pełni funkcjonalny autoloader dla wszystkich zdefiniowanych przestrzeni nazw oraz zależności.
<?php
// Plik: public/index.php (główny punkt wejścia aplikacji)
// Dołącz autoloader wygenerowany przez Composera
require_once __DIR__ .
'/../vendor/autoload.php
';
// Teraz możesz używać klas z przestrzeni MojaAplikacja\ bez ręcznego require
use MojaAplikacja\Kontrolery\DomowyKontroler;
use MojaAplikacja\Logika\UslugaUzytkownika;
$kontroler = new DomowyKontroler();
$usluga = new UslugaUzytkownika();
// ... reszta logiki aplikacji
?>
Używanie Composera i jego autoloadera jest standardem w nowoczesnym programowaniu PHP i znacznie upraszcza zarządzanie dużymi projektami oraz zależnościami od zewnętrznych bibliotek.
Podsumowanie Lekcji
W tej obszernej lekcji nauczyliśmy się, jak kluczowe dla organizacji kodu w PHP są Przestrzenie Nazw (Namespaces) i Automatyczne Ładowanie Klas (Autoloading). Zrozumieliśmy, że przestrzenie nazw pozwalają unikać konfliktów nazw i grupować kod w logiczne hierarchie, co jest niezbędne w większych projektach i przy korzystaniu z zewnętrznych bibliotek. Nauczyliśmy się definiować przestrzenie nazw, używać klas z nich za pomocą pełnych kwalifikowanych nazw oraz importować je i aliasować za pomocą instrukcji use
.
Następnie zgłębiliśmy mechanizm autoloadingu, który automatyzuje proces dołączania plików z definicjami klas. Poznaliśmy funkcję spl_autoload_register()
i zobaczyliśmy, jak stworzyć prosty autoloader. Skupiliśmy się na standardzie PSR-4, który definiuje sposób mapowania przestrzeni nazw na strukturę katalogów, co jest fundamentem interoperacyjności w ekosystemie PHP. Na koniec dowiedzieliśmy się, jak Composer, popularny menedżer zależności, automatyzuje generowanie autoloadera zgodnego z PSR-4 na podstawie konfiguracji w pliku composer.json
, co jest standardową praktyką w nowoczesnych aplikacjach PHP.
To była ostatnia lekcja w tym module. Gratulacje! Zdobyliście solidne podstawy Programowania Obiektowego w PHP, włączając w to klasy, obiekty, dziedziczenie, polimorfizm, interfejsy, cechy, a także kluczowe aspekty organizacji kodu jak przestrzenie nazw i autoloading. Ta wiedza stanowi fundament do tworzenia złożonych, dobrze zorganizowanych i łatwych w utrzymaniu aplikacji PHP oraz do efektywnego korzystania z nowoczesnych frameworków i bibliotek.
Zadanie praktyczne
Zorganizuj prosty projekt z użyciem przestrzeni nazw i stwórz podstawowy autoloader PSR-4 (bez Composera, dla celów edukacyjnych).
- Stwórz następującą strukturę katalogów w swoim projekcie:
projekt/ |-- src/ | |-- MojaBiblioteka/ | | |-- Narzedzia/ | | | |-- Kalkulator.php | | |-- Dane/ | | | |-- RepozytoriumUzytkownikow.php |-- public/ | |-- index.php |-- autoloader.php
- W pliku
src/MojaBiblioteka/Narzedzia/Kalkulator.php
zdefiniuj klasęKalkulator
w przestrzeni nazwMojaBiblioteka\Narzedzia
. Dodaj jej prostą metodę publiczną, np.dodaj(int $a, int $b): int
. - W pliku
src/MojaBiblioteka/Dane/RepozytoriumUzytkownikow.php
zdefiniuj klasęRepozytoriumUzytkownikow
w przestrzeni nazwMojaBiblioteka\Dane
. Dodaj jej prostą metodę, np.znajdzUzytkownika(int $id): string
. - W pliku
autoloader.php
napisz funkcję autoloadującą zgodną z PSR-4. Załóż, że prefix przestrzeni nazwMojaBiblioteka\
mapuje się na katalogsrc/MojaBiblioteka/
(względem katalogu, w którym jestautoloader.php
, czyli../src/MojaBiblioteka/
). Zarejestruj tę funkcję za pomocąspl_autoload_register()
. - W pliku
public/index.php
:- Dołącz plik
autoloader.php
(require_once __DIR__ . '/../autoloader.php ';
). - Użyj (zaimportuj) klasy
Kalkulator
iRepozytoriumUzytkownikow
. - Stwórz instancje tych klas i wywołaj ich metody, aby sprawdzić, czy autoloading działa poprawnie.
- Dołącz plik
Kliknij, aby zobaczyć przykładowe rozwiązanie
src/MojaBiblioteka/Narzedzia/Kalkulator.php:
<?php
namespace MojaBiblioteka\Narzedzia;
class Kalkulator
{
public function dodaj(int $a, int $b): int
{
return $a + $b;
}
}
?>
src/MojaBiblioteka/Dane/RepozytoriumUzytkownikow.php:
<?php
namespace MojaBiblioteka\Dane;
class RepozytoriumUzytkownikow
{
public function znajdzUzytkownika(int $id): string
{
return "Użytkownik o ID: " . $id . " (dane z repozytorium)";
}
}
?>
autoloader.php:
<?php
spl_autoload_register(function (string $className) {
// Definiujemy mapowanie prefixu przestrzeni nazw na katalog bazowy
// Klucz to prefix (zakończony \), wartość to ścieżka do katalogu bazowego (zakończona /)
$prefixes = [
"MojaBiblioteka\\" => __DIR__ .
'/src/MojaBiblioteka/
' // __DIR__ odnosi się do katalogu, w którym jest autoloader.php
// więc musimy cofnąć się do src/MojaBiblioteka
];
// Iterujemy po zarejestrowanych prefixach
foreach ($prefixes as $prefix => $baseDir) {
// Sprawdzamy, czy nazwa klasy zaczyna się od danego prefixu
$len = strlen($prefix);
if (strncmp($prefix, $className, $len) !== 0) {
// Nie, przejdź do następnego prefixu
continue;
}
// Pobierz względną nazwę klasy (bez prefixu przestrzeni nazw)
$relativeClass = substr($className, $len);
// Zastąp separatory przestrzeni nazw separatorami katalogów w względnej nazwie klasy,
// dodaj .php
$file = $baseDir . str_replace("\\", "/", $relativeClass) . ".php";
// Jeśli plik istnieje, załaduj go
if (file_exists($file)) {
require $file;
return; // Zakończ, klasa załadowana
}
}
// Opcjonalnie: można tu dodać logowanie, jeśli klasa nie została znaleziona przez żaden prefix
// error_log("Nie udało się załadować klasy: " . $className);
});
?>
public/index.php:
<?php
declare(strict_types=1);
echo "<h2>Testowanie Autoloadera PSR-4</h2>";
// Dołącz nasz autoloader
require_once __DIR__ .
'/../autoloader.php
';
// Import klas
use MojaBiblioteka\Narzedzia\Kalkulator;
use MojaBiblioteka\Dane\RepozytoriumUzytkownikow;
// Test Kalkulatora
$kalkulator = new Kalkulator();
$wynikDodawania = $kalkulator->dodaj(15, 7);
echo "Wynik dodawania (15 + 7): " . $wynikDodawania . "<br>";
// Test RepozytoriumUzytkownikow
$repo = new RepozytoriumUzytkownikow();
$daneUzytkownika = $repo->znajdzUzytkownika(101);
echo $daneUzytkownika . "<br>";
echo "<p>Jeśli widzisz wyniki powyżej, autoloader działa poprawnie!</p>";
/*
Upewnij się, że ścieżka w autoloader.php do katalogu src jest poprawna.
Jeśli autoloader.php jest w głównym katalogu projektu, to:
$prefixes = [
"MojaBiblioteka\\" => __DIR__ .
'/src/MojaBiblioteka/
'
];
Jeśli struktura jest taka jak w zadaniu (autoloader.php w głównym katalogu, a src jest podkatalogiem):
projekt/
|-- src/
|-- public/
|-- autoloader.php
To ścieżka w autoloader.php powinna być: `__DIR__ .
'/src/MojaBiblioteka/
'`
Natomiast w `public/index.php` dołączenie autoloadera: `require_once __DIR__ .
'/../autoloader.php
';` jest poprawne.
*/
?>
Zadanie do samodzielnego wykonania
Rozbuduj poprzednie zadanie o kolejną przestrzeń nazw i klasę, a następnie zmodyfikuj autoloader, aby obsługiwał oba mapowania.
- Dodaj nowy katalog i plik:
src/InnaFirma/Logowanie/Logger.php
. - W pliku
Logger.php
zdefiniuj klasęLogger
w przestrzeni nazwInnaFirma\Logowanie
. Dodaj jej prostą metodęlog(string $wiadomosc): void
, która wyświetla wiadomość. - Zmodyfikuj plik
autoloader.php
tak, aby obsługiwał dwa mapowania PSR-4:MojaBiblioteka\
mapowane nasrc/MojaBiblioteka/
InnaFirma\
mapowane nasrc/InnaFirma/
- W pliku
public/index.php
zaimportuj i użyj klasyLogger
, aby przetestować nowe mapowanie w autoloaderze.
FAQ - Przestrzenie Nazw i Autoloading
Czy mogę zdefiniować wiele przestrzeni nazw w jednym pliku PHP?
Tak, ale jest to rzadko stosowane i generalnie niezalecane dla przejrzystości. Można to zrobić używając składni z klamrami: namespace MojaPrzestrzen { /* kod */ } namespace InnaPrzestrzen { /* kod */ }
. Standardową praktyką jest jednak jedna przestrzeń nazw (lub jej brak dla kodu globalnego) na plik.
Jak odwołać się do klasy z globalnej przestrzeni nazw, będąc wewnątrz innej przestrzeni nazw?
Aby odwołać się do klasy z globalnej przestrzeni nazw (np. wbudowanej klasy PHP jak \DateTime
lub klasy zdefiniowanej bez namespace), należy poprzedzić jej nazwę odwrotnym ukośnikiem: $data = new \DateTime();
. Bez początkowego \
, PHP szukałoby klasy DateTime
w bieżącej przestrzeni nazw.
Czy use
wpływa na wydajność?
Samo użycie instrukcji use
ma znikomy wpływ na wydajność. Jest to głównie udogodnienie dla programisty, które jest rozwiązywane na etapie kompilacji skryptu. Autoloading może mieć pewien narzut przy pierwszym ładowaniu klasy, ale jest on zazwyczaj akceptowalny i kompensowany przez lepszą organizację i unikanie ładowania nieużywanych plików.
Co to jest PSR-0 i czym różni się od PSR-4?
PSR-0 to starszy standard autoloadingu. Główna różnica polega na tym, że PSR-0 wymagał, aby podkreślenia w nazwach klas były mapowane na separatory katalogów (np. Pear_Style_ClassName
). PSR-4 jest nowszy, prostszy i bardziej elastyczny, nie narzuca takiej konwencji dla podkreśleń i pozwala na bardziej bezpośrednie mapowanie prefixu przestrzeni nazw na katalog bazowy. Większość nowoczesnych projektów używa PSR-4.
Czy muszę używać Composera, aby korzystać z autoloadingu PSR-4?
Nie, nie musisz. Możesz napisać własny autoloader zgodny z PSR-4, tak jak pokazano w zadaniu praktycznym. Jednak Composer znacznie upraszcza ten proces, szczególnie w projektach z wieloma zależnościami, i jest zalecanym narzędziem w większości przypadków.
Czy wielkość liter ma znaczenie w przestrzeniach nazw i nazwach klas w PHP?
Nazwy klas, interfejsów i cech w PHP są niewrażliwe na wielkość liter (case-insensitive), np. new mojaKlasa()
zadziała, jeśli klasa jest zdefiniowana jako MojaKlasa
. Jednak nazwy przestrzeni nazw SĄ wrażliwe na wielkość liter w niektórych systemach plików (np. Linux) i dla spójności oraz zgodności z PSR-4, zawsze należy używać dokładnej wielkości liter zadeklarowanej w przestrzeni nazw i nazwie pliku.
Czy mogę używać aliasów dla przestrzeni nazw, a nie tylko dla klas?
Nie bezpośrednio dla całej przestrzeni nazw w taki sposób, jak dla klasy (use Moja\Długa\Nazwa as Krotka; $obj = new Krotka\Klasa();
nie zadziała). Aliasujesz pełną kwalifikowaną nazwę klasy, interfejsu, cechy, funkcji lub stałej. Możesz jednak zaimportować wiele klas z tej samej przestrzeni nazw: use Moja\Biblioteka\{KlasaA, KlasaB, Narzedzia\KlasaC as MojeNarzedzie};
(składnia grupowa od PHP 7.0).