Přejít k navigační liště

Zdroják » PHP » Symfony po krůčkách – ClassLoader

Symfony po krůčkách – ClassLoader

Články PHP

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.

Nálepky:

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í.

Komentáře

Subscribe
Upozornit na
guest
1 Komentář
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Jáchym Toušek

Composer autoloding lze ještě trochu vylepšit pomocí --classmap-authoritative.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.