RobotLoader: autoloading klas

RobotLoader to narzędzie, które zapewni Ci komfort automatycznego ładowania klas dla całej Twojej aplikacji, włącznie z bibliotekami stron trzecich.

  • pozbędziemy się wszystkich require
  • będą ładowane tylko potrzebne skrypty
  • nie wymaga ścisłych konwencji nazewnictwa katalogów czy plików
  • ekstremalnie szybki
  • żadnych ręcznych aktualizacji pamięci podręcznej, wszystko odbywa się automatycznie
  • dojrzała, stabilna i szeroko stosowana biblioteka

Możemy więc zapomnieć o tych znanych blokach kodu:

require_once 'Utils/Page.php';
require_once 'Utils/Style.php';
require_once 'Utils/Paginator.php';
// ...

Instalacja

RobotLoader można pobrać jako jeden samodzielny plik RobotLoader.php, który wstawisz za pomocą require do swojego skryptu i od razu masz do dyspozycji komfortowy autoloading dla całej aplikacji.

require '/path/to/RobotLoader.php';

$loader = new Nette\Loaders\RobotLoader;
// ...

Jeśli budujesz aplikację wykorzystującą Composer, możesz go zainstalować za pomocą niego:

composer require nette/robot-loader

Użycie

Podobnie jak robot Google przeszukuje i indeksuje strony internetowe, tak i RobotLoader przeszukuje wszystkie skrypty PHP i zapisuje, które klasy, interfejsy, traity i enumy w nich znalazł. Wyniki badań następnie zapisuje do cache i używa przy następnym żądaniu. Wystarczy więc określić, które katalogi ma przeszukiwać i gdzie zapisywać cache:

$loader = new Nette\Loaders\RobotLoader;

// katalogi, które RobotLoader ma indeksować (włącznie z podkatalogami)
$loader->addDirectory(__DIR__ . '/app');
$loader->addDirectory(__DIR__ . '/libs');

// ustawiamy cachowanie w katalogu 'temp'
$loader->setTempDirectory(__DIR__ . '/temp');
$loader->register(); // uruchamiamy RobotLoader

I to wszystko, od tej chwili nie musimy używać require. Super!

Jeśli RobotLoader napotka podczas indeksowania zduplikowaną nazwę klasy, rzuci wyjątek i poinformuje Cię o tym. RobotLoader również automatycznie aktualizuje cache, gdy ma załadować klasę, której nie zna. Zalecamy wyłączenie tej funkcji na serwerach produkcyjnych, zobacz Cachowanie.

Jeśli chcesz, aby RobotLoader pominął niektóre katalogi, użyj $loader->excludeDirectory('temp') (można wywoływać wielokrotnie lub przekazać więcej katalogów).

Domyślnie RobotLoader zgłasza błędy w plikach PHP rzucając wyjątek ParseError. Można to pominąć za pomocą $loader->reportParseErrors(false).

Aplikacja Nette

Wewnątrz aplikacji Nette, gdzie w pliku startowym Bootstrap.php używany jest obiekt $configurator, zapis można uprościć:

$configurator = new Nette\Bootstrap\Configurator;
// ...
$configurator->setTempDirectory(__DIR__ . '/../temp');
$configurator->createRobotLoader()
	->addDirectory(__DIR__)
	->addDirectory(__DIR__ . '/../libs')
	->register();

Analizator plików PHP

RobotLoader można również użyć wyłącznie do wyszukiwania klas, interfejsów, traitów i enumów w plikach PHP bez wykorzystywania funkcji autoloadingu:

$loader = new Nette\Loaders\RobotLoader;
$loader->addDirectory(__DIR__ . '/app');

// przeszukuje katalogi w poszukiwaniu klas / interfejsów / traitów / enumów
$loader->rebuild();

// zwraca tablicę par klasa => nazwa pliku
$res = $loader->getIndexedClasses();

Nawet przy takim użyciu można wykorzystać cache. Dzięki temu przy ponownym skanowaniu nie będą ponownie analizowane niezmienione pliki:

$loader = new Nette\Loaders\RobotLoader;
$loader->addDirectory(__DIR__ . '/app');

// ustawiamy cachowanie w katalogu 'temp'
$loader->setTempDirectory(__DIR__ . '/temp');

// przeszukuje katalogi z wykorzystaniem cache
$loader->refresh();

// zwraca tablicę par klasa => nazwa pliku
$res = $loader->getIndexedClasses();

Cachowanie

RobotLoader jest bardzo szybki, ponieważ sprytnie wykorzystuje cache.

Podczas rozwoju praktycznie nie zauważasz, że działa w tle. Bieżąco aktualizuje cache, ponieważ zakłada, że klasy i pliki mogą powstawać, znikać, zmieniać nazwy itp. I nie skanuje ponownie plików, które się nie zmieniły.

Podczas wdrażania na serwerze produkcyjnym zalecamy natomiast wyłączenie aktualizacji cache za pomocą $loader->setAutoRefresh(false) (w aplikacji Nette dzieje się tak automatycznie), ponieważ pliki się nie zmieniają. Jednocześnie konieczne jest wtedy przy wgrywaniu nowej wersji na hosting usunięcie cache.

Pierwsze skanowanie plików, gdy cache jeszcze nie istnieje, może w przypadku większych aplikacji oczywiście chwilę potrwać. RobotLoader ma wbudowaną prewencję przed cache stampede. Jest to sytuacja, gdy na serwerze produkcyjnym pojawi się większa liczba równoczesnych żądań, które uruchomią RobotLoader, a ponieważ cache jeszcze nie istnieje, wszystkie zaczęłyby skanować pliki. Co nieproporcjonalnie obciążyłoby serwer. Na szczęście RobotLoader działa tak, że przy wielu równoczesnych żądaniach pliki indeksuje tylko pierwszy wątek, tworzy cache, pozostałe czekają, a następnie wykorzystują cache.

PSR-4

Obecnie można do autoloadingu używać Composera przy zachowaniu PSR-4. Upraszczając, jest to system, w którym przestrzenie nazw i nazwy klas odpowiadają strukturze katalogów i nazwom plików, czyli np. App\Core\RouterFactory będzie w pliku /path/to/App/Core/RouterFactory.php.

RobotLoader nie jest związany z żadną stałą strukturą, dlatego przydaje się w sytuacjach, gdy nie do końca odpowiada Ci posiadanie tak samo zaprojektowanej struktury katalogów jak przestrzenie nazw w PHP, lub gdy rozwijasz aplikację, która historycznie takich konwencji nie wykorzystuje. Możliwe jest również używanie obu loaderów jednocześnie.

wersja: 4.0