Symfony po krůčkách – ClassLoader

Pokud chceme psát v naší PHP aplikaci hezky objektově, je třeba ty objekty (třídy) nějak načítat. Bezpochyby každý z vás někdy přemýšlel, jak to udělat nejlépe. Symfony k tomu nabízí komponentu ClassLoader.

Seriál: Symfony po krůčkách (18 dílů)

  1. Symfony po krůčkách – Event Dispatcher 30.11.2015
  2. Symfony Console jako první rande se Symfony 7.12.2015
  3. Symfony po krůčkách – Filesystem a Finder 14.12.2015
  4. Symfony po krůčkách – Paralýza možností? OptionsResolver tě zachrání 21.12.2015
  5. Symfony po krůčkách – spouštíme procesy 4.1.2016
  6. Symfony po krůčkách – Translation – překlady jednoduše 11.1.2016
  7. Symfony po krůčkách – Validator (1) 18.1.2016
  8. Symfony po krůčkách – Validator (2) 25.1.2016
  9. Symfony po krůčkách – Routing 1.2.2016
  10. Symfony po krůčkách – MicroKernel 9.2.2016
  11. Konfigurujeme Symfony pomocí YAMLu 16.2.2016
  12. Symfony po krůčkách – oblékáme MicroKernel 23.2.2016
  13. Symfony po krůčkách – ClassLoader 29.2.2016
  14. Symfony po krůčkách – Twig 8.3.2016
  15. Symfony po krůčkách – Twig II. 15.3.2016
  16. Symfony po krůčkách – DomCrawler a CssSelector 23.3.2016
  17. Symfony po krůčkách – HTTP fundamentalista 12.4.2016
  18. Symfony po krůčkách – ušli jsme pořádný kus 19.4.2016

Snad každý někdy řešil, jak nejlépe načítat třídy v PHP. Pamatuji si začátky a psaní require_once pro všechny classy do bootstrap souborů.

// boostrap.php
require_once __DIR__ . '/src/App.php';
...

Později spl_autoload_register  a další „vylepšení“ první ukázky. Toto vše bylo samozřejmě ještě předtím, než přišel Composer a stačilo napsat pouze

require_once __DIR__ . '/vendor/autoload.php';

O víc se už nemusíte starat. Tedy, pokud dodržujete alespoň nějaký standard (PSR-0 nebo PSR-4). Stačí pouze dobře nastavit composer.json.

// composer.json
...
"autoload": {
    "psr-4": {
        "MF\\": "src/"
    }
},
...

Composer autoload vs Symfony ClassLoader

Určitě se tedy ptáte, proč zmiňuji Symfony ClassLoader, když už jsem vlastně řekl, že celý problém vyřešil autoload od Composeru. Máte pravdu – Composer autoloader řeší celou situaci ohledně načítání tříd sám. A řekl bych, že skvěle.

Proč tedy používat Symfony ClassLoader komponentu?

Upřímně – nevím. Nenašel jsem žádný rozumný důvod pro běžné aplikace.

Napadlo mě ale několik důvodů, proč by to přece jen mohl být dobrý nápad:

  1. nemůžete nebo nechcete z nějakého důvodu používat Composer
  2. potřebujete řešit výkon autoloadování natolik, že ani Composer autoload (s optimize apod.) nestačí

Z mého pohledu tedy v 99% případů stačí composer autoload. Obvzláště pak, když autoloaderu pomůžete těmito příkazy:

$ composer dump-autoload --optimize
$ composer install --optimize-autoloader 

Ukázková aplikace

Pro ukázku jsem si připravil jednoduchou aplikaci na výpis „Hello world!„. Úmyslně jsem tuto banalitu rozdělil na více tříd, aby bylo co načítat. Na kód se můžete podívat na githubu.

├── README.md
├── composer.json
├── composer.lock
├── index.php
├── index_apc.php
├── index_apc_unregister.php
├── index_composer.php
├── index_map.php
├── index_psr4.php
├── index_wincache.php
├── index_xcache.php
├── src
│   ├── App.php
│   └── Render
│       ├── MessageRender.php
│       ├── Render.php
│       └── RenderInterface.php
└── src_psr0
    └── MF
        ├── App.php
        └── Render
            ├── MessageRender.php
            ├── Render.php
            └── RenderInterface.php
<?php
// index.php
require_once __DIR__ . '/vendor/symfony/class-loader/ClassLoader.php';

use MF\App;
use MF\Render\Render;
use Symfony\Component\ClassLoader\ClassLoader;

$loader = new ClassLoader();
$loader->addPrefix('MF', __DIR__ . '/src_psr0');
$loader->register();

$app = new App(new Render());

$app->renderResponse();

Třída App pouze zabaluje základní zpracování requestu.

Třída RenderInterface(resp. jeho implementace) se stará o samotné vypsání obsahu stránky – „Hello world!“.

Abychom mohli třídy používat, PHP script musí třídy znát. V index.php je vidět použití Symfony komponenty ClassLoader, o které tento článek pojednává. Různých implementací class loaderů od Symfony je víc a budu se jim jednotlivě věnovat dále.

Symfony class loadery

Nyní bych rád popsal jednotlivé implementace ClassLoaderů od Symfony – jejich použití, výhody a nevýhody.

Psr0 ClassLoader

Jak již z názvu vyplývá, Psr0 ClassLoader autoloaduje Psr0 strukturu – tzn: \{Vendor Name}\({Namespace}\)*{Class Name} . Použití Psr0 ClassLoaderu jste mohli vidět již na začátku článku.

// index.php
...
$loader = new ClassLoader();
$loader->addPrefix('MF', __DIR__ . '/src_psr0');
$loader->register();
...

Psr4 ClassLoader

Psr4 ClassLoader autoloaduje podle struktury Psr4 – tzn: \{NamespaceName}(\{SubNamespaceNames})*\{ClassName}. Použití je velmi podobné Psr0 ClassLoaderu.

// index_psr4.php
...
$loader = new Psr4ClassLoader();
$loader->addPrefix('MF', __DIR__ . '/src');
$loader->register();
...

MapClassLoader

Dovoluje vytvořit mapu tříd, podle které se bude autoloading řídit. Mapa je v podstatě klasické pole, ve kterém se definují cesty k souborům podle názvu tříd.

Hodí se hlavně na třídy třetích stran, které nepodporují Psr0/4.

Ve výchozím nastavení se MapClassLoader přidává až za ostatní autoloading. Pokud chcete použít MapClassLoader jako výchozí, předejte true do registrační metody. Pak bude MapClassLoader předán před ostatní autoloading.

// index_map.php
...
$loader = new MapClassLoader([
    'MF\\App' => __DIR__ . '/src/App.php',
    'MF\\Render\\RenderInterface' => __DIR__ . '/src/Render/RenderInterface.php',
    'MF\\Render\\Render' => __DIR__ . '/src/Render/Render.php',
]);
$loader->register();
...

Možná zrychlení

Použití autoloadingu v každém requestu může být zbytečně náročné. Proto je dobré skriptu ulehčit práci a výslednou mapu tříd si uložit do cache. K tomuto slouží cachovací třídy (ApcClassLoader, …). Je možné definovat i prefix pro cache, pro jednoduché dohledání / smazání.

Tyto třídy fungují jako adapter nad ClassLoadery, resp. nad čímkoliv, co implementuje metodu findFile($class). Pro ukázku jsem se rozhodl použít Psr4ClassLoader jako základní autoloading nástroj.

ApcClassLoader

ApcClassLoader potřebuje ke svému fungování PHP extensionu apc (Alternative PHP Cache).

// index_apc.php
...
$loader = new Psr4ClassLoader();
$loader->addPrefix('MF', __DIR__ . '/src');

$loader = new ApcClassLoader('apc.prefix', $loader);
$loader->register();
...

XCacheClassLoader

XCacheClassLoader využívá k ukládání xcache.

// index_xcache.php
...
$loader = new Psr4ClassLoader();
$loader->addPrefix('MF', __DIR__ . '/src');

$loader = new XcacheClassLoader('cache.prefix', $loader);
$loader->register();
...

WinCacheClassLoader

WinCacheClassLoader, stejně jako dvě předchozí instance, potřebuje PHP extensionu wincache. Tato implementace slouží k použití PHP na Windows.

// index_wincache.php
...
$loader = new Psr4ClassLoader();
$loader->addPrefix('MF', __DIR__ . '/src');

$loader = new WinCacheClassLoader('cache.prefix', $loader);
$loader->register();
...

Co jsme si dnes ukázali

  • rozdíl mezi Composer autoloadem a Symfony ClassLoaderem
  • jednoduché použití ClassLoaderů od Symfony
  • případné možnosti zrychlení (cachování)

Pokud byste se chtěli podívat na ClassLoader podrobněji, můžete využít dokumentaci, kde najdete více informací.

Jsem převážně PHP programátor. Je mi ale docela blízký i JavaScript, .NET a další. Jsem zastáncem čistého kódu a kvalitní práce.

Aktuálně pracuji v LMC jako lead engineer týmu zabývajícím se vzdělávacími portály (seduo.cz).

Komentáře: 1

Přehled komentářů

Jáchym Toušek
Zdroj: https://www.zdrojak.cz/?p=17170