08
marca
2009
W nawiazaniu do wpisu Prosty loader plików w PHP postanowiłem podzielić się moimi przemyśleniami w temacie pisania loaderów klas w PHP.
Ja polecam zasadę "convention over configuration". Nawet takie configuration jak podawanie: Load::load('folder1/folder2/*'); wydaje mi się zbędne. Tym bardziej polecane w komentarzach pomysły statycznych listy klucz-wartość z klasami i ścieżkami do plików z klasą wydaje mi się być nie na miejscu.
Więc skoro dysponowałbym czystym projektem i nic by mnie nie ograniczało, to użyłbym czegoś w tym stylu:
Teraz wystarczy tylko w standardowej metodzie __autoload() dopisać do tego odpowiednią obsługę, czyli zamianę znaków / na _ i można już używać wszystkich klas dostępnych w aplikacji w ogóle nie myśląc o ich ładowaniu. A także bez nadmiarowego doładowywania klas, których się nie potrzebuje. Dlatego w przykładowym pliku index.php w katalogu nadrzędnym dla wszystkich z klasami powinien być kod:
<?php
define("APP_PATH", dirname(__FILE__));
function __autoload($class) {
$filepath = str_replace('_', '/', $class).".php";
require_once APP_PATH.'/'.$filepath;
}
?>
* Oczywiście, nie twierdzę, że jest to moje autorskie rozwiąznie. Jednak wydaje mi się jak najbardziej odpowiednie do projektów w których jest skomplikowania hierarchia klas. Ciekaw jestem co o nim sądzicie.
Mnie osobiście takie rozwiązanie podoba się z dwóch powodów:
1. Istotnie nie ładuje się niepotrzebnych klas
2. Wymusza stosowanie określonej struktury katalogów, co pomaga utrzymać porządek w projekcie.
Jednak de facto mój kod bynajmniej nie miał mi służyć tylko do ładowania plików z klasami PHP, tylko ogólnie do ładowania wielu plików naraz :-).
Tak czy inaczej powyższy sposób przypadł mi go gustu.
Osobiście używam podobnego rozwiązania, ale z założenia konceptowego mam po prostu $base->className i ładowaniem zajmuje się __get()
No i przydał by się jakiś Throw w przypadku Twojego rozwiązania. U mnie sobie rzucam errora i w wypadku jakiegoś trywialnego obiektu robię stdClass coby skrypt mógł przejść gdzieś dalej (TYLKO jeżeli jest to na prawdę trywialny obiekt).
Ukrywanie błędów – nawet w sposób typu „ zwracam stdClass” wydaje się nieelegancki. Gdyż w ten sposób sam przed sobą chowasz błędy – które są IMHO jak najbardziej na miejscu. Przecież nie możesz oczekiwać, że stdClass ma takie same właściwości co Twoja klasa. ;-) Więc, zwrócenie wyjątku, gdy pliku nie ma to ok, ale ukrywanie błędów i przenoszenie ich na dalszy plan, gdzie jakiś inny obiekt korzysta z właściwości obiektu który jest niewłaściwy to jest trochę nieeleganckie. Mój kawałek kodu – nie miał być rozwiązaniem finalnym problemu ładowania klas, a bardziej chciałem przedstawić koncepcję, więc pominąłem zbędny kod odpowiedzialny za obsługę błędów zaciemniający całe rozwiązanie – ufając PHPowi, że sam powie „Class not found”, a programista dopisze to czego brakuje. ;-)
Rafał – nie ukrywam, rzucam wyjątek, więc sterowanie wraca w miejsce, które przygotowane jest na przechwycenie wyjątku i zastąpienie obiektu dummy-klasą. Może to być np. obiekt cache – skrypt dalej stwierdza, że cache jest przedawnione i wykonuje się inna gałąź kodu.
To rozwiązanie funkcjonuje np w Zend Framework. I paru innych.
Co do __autoload i wyjątków widzę taki problem, że … z __autoload nie możesz rzucić wyjątku.
Używam tego dokładnie tak samo :) (pomysł z Zenda), bardzo wygodne i nie trzeba się martwić o ładowanie czegokolwiek.