Proč Jet používá .php soubory jako úložiště dat a zdroj konfigurace?
Zarazili vás proč jste v adresáři ~/application/config našli soubor db.php a ne třeba db.ini, nebo db.xml? Nebo proč je v adresáři ~/application/data seznam nainstalovaných modulů installed_modules_list.php a ne něco jiného? Má to své technické a především měřitelné a porovnatelné důvody.
Nejlepší bude ukázat si možnosti a různé alternativy například uklání konfigurace a rovnou na nich demonstrovat výhody a nevýhody daného řešení.
Alternativa: .ini soubory
Výhody:
- PHP obsahuje funkce parse_ini_file a parse_ini_string - není tedy nutné nic extra implementovat za účelem čtení dat.
- I když jsou možnosti .ini souborů opravdu slušné, stále jsou limitované a ne tak flexibilní.
- PHP má implementované parsování, ale ne vytváření .ini souborů. To by bylo nutné implementovat. Ale to není zas tak zásadní problém.
- Při nějakém nedopatření a přímém zpřístupnění adresáře konfigurace přes URL jsou .ini soubory snadno přímo čitelné ...
Alternativa: XML
Výhody:
- Je možné smysluplně uložit vlastně libovolná data.
- XML je široce podporovaný standard s dobrou podporou v PHP.
- Jak si ukážeme níže, tak je poměrně významná technická režie pro zpracování XML.
- Při nějakém nedopatření a přímém zpřístupnění adresáře konfigurace přes URL jsou XML soubory snadno přímo čitelné ...
Alternativa: JSON
Výhody:
- Opět je možné smysluplně uložit vlastně libovolná data.
- I JSON je dnes široce podporovaný standard s dobrou podporou v PHP.
- I zde si dále předvedeme režii pro zpracování ...
- Při nějakém nedopatření a přímém zpřístupnění adresáře konfigurace přes URL jsou JSON soubory snadno přímo čitelné ...
Alternativa: serializovaná data pomocí PHP funkce
Výhody:
- Je možné uložit vlastně libovolná data.
- Relativně rychlé zpracování.
- Vše potřebné má PHP v sobě.
- Není to ideální formát pro člověka a je vhodné, aby konfigurace a další data byla pro vývojáře čitelná a také ručně upravitelná.
- Při nějakém nedopatření a přímém zpřístupnění adresáře konfigurace přes URL jsou soubory snadno přímo čitelné ...
Alternativa: nějaký speciální datový formát (více či méně standardní)
Výhody:
- ... žádné objektivní výhody
- Nutnost implementace a údržba neužitečného kódu (neobhajitelné náklady - neobhajitelná investice času a peněz).
- Téměř jistě nepříjemná technická režie.
- Při nějakém nedopatření a přímém zpřístupnění adresáře konfigurace přes URL jsou soubory snadno přímo čitelné ...
Současné řešení: .php soubory obsahující deklaraci pole
Výhody:
- Jak si ukážeme v porovnání, tak objektivně technicky nejrychlejší řešení (z několika důvodů).
- Snadné ukládání a čtení libovolných dat.
- Pro vývojáře snadno čitelné a modifikovatelné soubory ve formátu, který moc dobře zná - je mu vlastní.
- Pokud by se díky chybě v nastavení bylo možné dostat do adresáře ~/application/config přes URL, tak se takto jednoduše stejně nic nezobrazí. Je to nesrovnatelně bezpečnější.
- PHP pracuje se soubory jako s jinými skripty. To znamená, že na ně může (ale nemusí) použít třeba OPCache a je tu možnost mít konfiguraci hezky naparsovanou v paměti. Tím se může doslova škrtnou spousta režijní činnosti při zpracování požadavku.
- .... někomu to může připadat na první pohled málo "punk" a cool :-)
- Je nutné počítat s případným efektem OPCache (a tuto keš promazávat, pokud je to třeba).
Porovnání
Na základě argumentů se dá předpokládat, že PHP soubory budou nejrychlejší a tedy technicky nejlepší řešení. Teorii je ale nutné ověřit. A výsledek takového ověření si ukážeme.
Nejprve co budeme porovnávat. Ze všech alternativ jsem vybral dva kandidáty - konkurenční technologie, které mohou být brány v úvahu a to: JSON a XML. Důvod? .ini soubory jsou poměrně málo flexibilní (respektive ne tak jak bych si přál), serializovaná data nejsou vhodná pro případný zásah člověkem a speciální datový formát vůbec nezvažuji - není k tomu důvod, když jsou k dispozici funkční a plně dostatečné alternativy.
Metoda porovnání
Je nutné srovnávat srovnatelné a omezit vedlejší vlivy. Tedy vytvořil jsem tři samostatné PHP skripty zcela bez jakéhokoliv frameworku, čistě krátké syrové jednoúčelové skripty.
Každý skript měl provést totéž a to načíst zcela identická data. Respektive identická v tom, že v nich byla vždy stejná informace, ale pokaždé v jiném datovém formátu.
Skripty jsem umístil na můj lokální webserver. Nepoužil jsem žádný sdílený hosting podobně. Postupoval jsem tak, abych měl prostředí plně pod kontrolou a věděl že na daném stroji běží v daný moment právě jen daný test.
Pomocí jednoduchého nástroje Apache Benchmark jsem otestoval výkonnost a propustnost daných skriptů. Vždy za stejných podmínek, aby bylo jasné, které čtení dat aplikaci pod zátěží ovlivní nejvíc.
Načítaná data
Podoba načítaných informací v datech byla při měření zcela identická. Pouze se lišil datový formát jednotlivých souborů:
data.php
return [
'connections' => [
'default' => [
'host' => 'localhost',
'port' => 1234,
'username' => 'user',
'password' => '*********',
],
'custom' => [
'host' => 'somewhere.universe',
'port' => 4321,
'username' => 'user',
'password' => '*********',
],
]
];
data.json
{
"connections": {
"default": {
"host": "localhost",
"port": 1234,
"username": "user",
"password": "*********"
},
"custom": {
"host": "somewhere.universe",
"port": 4321,
"username": "user",
"password": "*********"
}
}
}
data.xml
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<connections>
<connection>
<name>default</name>
<host>localhost</host>
<port>1234</port>
<username>user</username>
<password>*********</password>
</connection>
<connection>
<name>custom</name>
<host>somewhere.universe</host>
<port>4321</port>
<username>user</username>
<password>*********</password>
</connection>
</connections>
</config>
Testovací skripty
Účel testovacích skriptů byl jeden jediný a to přečíst data ze souboru a připravit je do dále zpracovatelné podoby. Nic víc a zcela bez závislosti na čemkoliv.
test_php.php
$data = require 'data.php';
//var_dump($data);
test_json.php
$data = file_get_contents( 'data.json' );
$data = json_decode( $data, true );
//var_dump($data);
test_xml.php
$data = simplexml_load_file('data.xml');
//var_dump($data);
Průběh měření
Měření proběhlo na laptopu s CPU i7-8550U, 16GiB RAM, SSD, OS: GNU/Linux Ubuntu 20.04.3 LTS, PHP 8.0.14, Apache/2.4.52
Testovací skripty na samostatném virtuálu webserveru Apache. Vše nepotřebné pro test povypínáno, deaktivováno.
Parametry Apache Benchmark: Počet požadavků 100 000. Konkurence: 100.
Podmínky pro všechny testy stejné.
Poměřovaná výstupní hodnota: Počet požadavků za sekundu podle Apache Benchmark. Každý test opakován 3x, porovnávána bude výsledná průměrná hodnota.
Výsledek a závěr
PHP
1. měření | 19845.93 rq/s |
2. měření | 19704.98 rq/s |
3. měření | 19804.91 rq/s |
Výsledný průměr | 19785.27 rq/s |
1. měření | 16920.07 rq/s |
2. měření | 16210.12 rq/s |
3. měření | 16420.59 rq/s |
Výsledný průměr | 16516,93 rq/s |
1. měření | 15438.38 rq/s |
2. měření | 15598.49 rq/s |
3. měření | 15546.71 rq/s |
Výsledný průměr | 15527,86 rq/s |
Závěr
Na základě objektivních faktů se dá říct, že zvolený způsob ukládání konfigurace a metadat aplikace je nejlepší. Má nejnižší režii (nejméně brzdí aplikaci), je pro vývojáře snadno čitelný a upravitelný, nevyžaduje žádnou speciální implementaci a žádný nadbytečný kód. Daný přístup je rovněž nejbezpečnější. Jako alternativa by připadal v úvahu formát JSON, ale PHP je přece jen o něco rychlejší a bezpečnější.