Pokud jste vyvíjeli PHP posledních pár let, pravděpodobně si uvědomujete problémy s tímto jazykem. Často můžete slyšet, že je to roztříštěný jazyk, hackerský nástroj, že nemá skutečnou specifikaci a podobně. Realita je taková, že PHP se v poslední době hodně rozrostlo. Verze PHP 5.4 ji přiblížila k dokončení objektový model a poskytl mnoho nových funkcí.

A to je všechno samozřejmě dobré, ale co frameworky? V PHP je jich spousta. Stačí začít hledat a pochopíte, že nebudete mít dost života na to, abyste je všechny studovali, protože se neustále objevují nové frameworky a v každém se vymýšlí něco vlastního. Jak z toho tedy udělat něco, co neodcizuje vývojáře a usnadňuje přenos funkcí z jednoho frameworku do druhého?

Co je PHPFIG

PHP-FIG (PHP Framework Interop Group) je organizovaná skupina vývojářů, jejichž cílem je najít způsoby, jak spolupracovat několik frameworků.

Jen si to představte: aktuálně podporujete projekt Zend Framework, který potřeboval modul nákupního košíku. Už jste takový modul napsali pro předchozí projekt, který byl na Symphony. Proč to neudělat znovu? Naštěstí jsou ZendF i Symphony součástí PHP-FIG, takže je možné importovat modul z jednoho frameworku do druhého. Není to skvělé?

Pojďme zjistit, jaké rámce jsou součástí PHP-FIG

Členové PHP-FIG

Každý vývojář může přidat svůj rámec do seznamu přispěvatelů PHP-FIG. Za to však budete muset zaplatit určitou částku, takže pokud nemáte podporu komunity, pravděpodobně s tím nebudete souhlasit. To má zabránit registraci milionů mikrorámců bez reputace.

Současní členové:

Co je PSR?

PSR (PHP Standards Recommendations) - standardní doporučení, výsledek PHP-FIG. Někteří členové skupiny navrhují pravidla pro každou PSR, jiní hlasují pro tato pravidla nebo pro jejich zrušení. Diskuse probíhá ve Skupinách Google a sady PSR jsou k dispozici na oficiálních webových stránkách PHP-FIG.

Podívejme se na některé PSR:

Prvním krokem ke sjednocení rámců je mít společnou adresářovou strukturu, a proto byl přijat společný standard automatického načítání.

  1. Jmenný prostor (namespace) a třída musí mít strukturu \\(\)*.
  2. Každý jmenný prostor musí obsahovat mezeru nejvyšší úrovně ("Název dodavatele").
  3. Každý jmenný prostor může mít libovolný počet úrovní.
  4. Každý oddělovač jmenného prostoru je při načtení převeden na DIRECTORY_SEPARATOR.
  5. Každý znak „_“ v CLASS NAME je převeden na DIRECTORY_SEPARATOR.
  6. Plně kvalifikovaný jmenný prostor a třída jsou při načtení připojeny s ".php".

Příklad funkce automatického načítání:

PSR-1 - Základní kódovací standard

Tyto PSR regulují základní standardy, jejichž hlavní myšlenkou je, že pokud všichni vývojáři používají stejné standardy, pak lze bez problémů provést portování kódu.

  1. Soubory by měly používat pouze značky
  2. Soubory musí používat pouze UTF-8 bez kódování BOM.
  3. Názvy prostorů a třídy musí následovat PSR-0.
  4. Názvy tříd musí být deklarovány v notaci StudlyCaps.
  5. Konstanty třídy musí být deklarovány velkými písmeny oddělenými podtržítky.
  6. Metody musí být deklarovány v notaci camelCase.

PSR-2 - Průvodce stylem kódování

Toto jsou rozšířené instrukce pro PSR-1, popisující pravidla formátování kódu.

  1. Kód musí odpovídat PSR-1.
  2. Místo tabulátorů by měly být použity 4 mezery.
  3. Délka řetězce by neměla být striktně omezena, doporučená délka je do 80 znaků.
  4. Za deklarací jmenného prostoru musí být jeden prázdný řádek.
  5. Závorky pro třídy by se měly otevírat na dalším řádku za deklarací a zavírat za tělem třídy (stejné pro metody).
  6. Musí být definována viditelnost metod a vlastností (veřejné, soukromé).
  7. Otevírací konzoly pro řídicí konstrukce musí být na stejné linii, uzavírací konzoly musí být na další řadě za tělesem konstrukce.
  8. Po otevření závorek metod řídicí struktury a před uzavřením závorek se neumisťují žádné mezery.

PCR-3 - Logger Interface

PCR-3 reguluje protokolování, zejména devět hlavních metod.

  1. LoggerInterface poskytuje 8 metod pro protokolování osmi úrovní RFC 5424 (ladění, upozornění, varování, chyba, kritická, výstraha, nouzový stav).
  2. Devátá metoda log() bere jako svůj první parametr úroveň varování. Volání metody s parametrem úrovně výstrahy musí vrátit stejný výsledek jako volání metody určité úrovně protokolu (log(ALERT) == alert()). Volání metody s nedefinovanou úrovní varování musí vyvolat výjimku Psr\Log\InvalidArgumentException.

Stejně jako PSR-0 poskytuje PSR-4 vylepšené metody automatického načítání

  1. Termín "třída" odkazuje na třídy, rozhraní, vlastnosti a další podobné struktury.
  2. Plně kvalifikovaný název třídy má následující tvar: \ (\)*\
  3. Při načítání souboru, který odpovídá plně kvalifikovanému názvu třídy:
  • Souvislá řada jednoho nebo více úvodních jmenných prostorů, s výjimkou úvodního oddělovače jmenných prostorů, v plně kvalifikovaném názvu třídy odpovídá alespoň jednomu "kořenovému adresáři".
  • Názvy adresářů a podadresářů se musí shodovat s velikostí písmen v oboru názvů.
  • Konec celého názvu třídy odpovídá názvu souboru s koncovkou .php. Velikost písmen v názvu souboru se musí shodovat s malými a velkými písmeny na konci celého názvu třídy.
  • Implementace autoloaderu nesmí vyvolávat výjimky, generovat chyby jakékoli úrovně a nesmí vracet hodnotu.

Závěr

PHP-FIG mění způsob, jakým jsou frameworky psány, ale ne jak fungují. Klienti často vyžadují, abyste pracovali s existujícím kódem v rámci nebo specifikovali, se kterým rámcem byste měli na projektu pracovat. Doporučení PSR v tomto ohledu vývojářům značně usnadňují život, což je skvělé!

PHP programovací jazyk ušel dlouhou cestu od nástroje pro vytváření osobních stránek k univerzálnímu jazyku. Dnes je nainstalován na milionech serverů po celém světě a používají jej miliony vývojářů, kteří vytvářejí širokou škálu projektů.

Je snadné se naučit a velmi populární, zejména mezi začátečníky. Proto po vývoji jazyka následoval mohutný rozvoj komunity kolem něj. Obrovské množství skriptů, pro všechny příležitosti, různé knihovny, frameworky. Absence jednotného designu a standardů kódování vedla ke vzniku obrovské vrstvy informačních produktů postavených na vývojářských vlastních principech tohoto produktu. To bylo zvláště patrné při práci s různými PHP frameworky, který dlouhou dobu představoval uzavřený ekosystém, nekompatibilní s jinými frameworky, a to přesto, že úkoly, které řeší, jsou často podobné.

V roce 2009 se vývojáři několika frameworků dohodli na vytvoření komunity PHP Framework Interop Group (PHP-FIG), který by vypracoval doporučení pro vývojáře. Je důležité zdůraznit, že o tom nemluvíme normy ISO, správnější je mluvit o doporučeních. Ale od těch, kteří tvořili php-obr komunita vývojářů představují hlavní frameworky, jejich doporučení mají vážnou váhu. Podpěra, podpora standardy PSR (standardní doporučení PHP). umožňuje interoperabilitu, která usnadňuje a urychluje vývoj konečného produktu.

Celkem je v době psaní tohoto článku 17 norem a 9 z nich je schváleno, 8 je ve fázi návrhu, je aktivně diskutováno, 1 norma není doporučena k použití.

Nyní pojďme přímo k popisu každého standardu. Všimněte si, že zde nebudu podrobně procházet každý standard, ale spíše malý úvod. Článek se také bude zabývat pouze těmi PSR standardy, které jsou oficiálně přijímány, tzn. jsou ve stavu Přijato.

PSR-1. Hlavní standard kódování

Představuje nejobecnější pravidla, jako je například použití PHP tagy, kódování souborů, oddělení místa deklarace funkce, třídy a místa jejich použití, pojmenování tříd, metody.

PSR-2. Průvodce stylem kódu

Navazuje na první standard a upravuje používání tabulátorů v kódu, zalomení řádků, maximální délku řádků kódu, pravidla pro navrhování řídicích struktur atd.

PSR-3. Rozhraní protokolování.

Tento standard je navržen tak, aby umožňoval (logování) přihlašování do aplikací napsaných v PHP.

PSR-4. Standardní automatické načítání

Toto je pravděpodobně nejdůležitější a nezbytný standard, kterému se budeme věnovat v samostatném podrobném článku. Třídy, které implementují PSR-4, lze načíst pomocí jediného automatického zavaděče, což umožňuje použití dílů a komponent z jednoho rámce nebo knihovny v jiných projektech.

PSR-6. rozhraní mezipaměti

Ukládání do mezipaměti se používá ke zlepšení výkonu systému. A PSR-6 umožňuje standardní ukládání a načítání dat z cache pomocí jednotného rozhraní.

PSR-7. rozhraní zpráv HTTP

Při psaní více či méně složitém stránky v PHP, téměř vždy se musí pracovat HTTP hlavičky. Samozřejmě, jazyk PHP nám poskytuje hotové možnosti práce s nimi, jako je kupř superglobální pole $_SERVER, funkce záhlaví(), setcookie() atd., jejich ruční analýza je však plná chyb a ne vždy je možné vzít v úvahu všechny nuance práce s nimi. A tak, aby se usnadnila práce vývojáře, stejně jako rozhraní interakce s HTTP protokol tato norma byla přijata. O tomto standardu budu hovořit podrobněji v některém z následujících článků.

PSR-11. Rozhraní kontejneru

Při psaní PHP programyČasto musíte používat komponenty třetích stran. A abychom se v tomto lese závislostí neztratili, byly vynalezeny různé metody správy závislostí kódu, často vzájemně nekompatibilní, což tento standard vede ke společnému jmenovateli.

PSR-13. Hypermediální odkazy

Toto rozhraní je navrženo tak, aby usnadnilo vývoj a používání rozhraní pro programování aplikací ( API).

PSR-14. Jednoduché rozhraní pro ukládání do mezipaměti

Jde o pokračování a vylepšení standardu PSR-6

Tak jsme dnes uvažovali standardy PSR. Pro aktuální informace o stavu norem prosím kontaktujte

16.09.2016

Pokusme se zjistit, jak zlepšit výkon aplikačního serveru založeného na php-fpm, a také vytvořit kontrolní seznam pro kontrolu konfigurace fpm procesu.

Nejprve se vyplatí určit umístění konfiguračního souboru fondu. Pokud jste nainstalovali php-fpm ze systémového úložiště, pak konfigurace fondu www bude umístěn kolem /etc/php5/fpm/pool.d/www.conf . Pokud používáte vlastní sestavení nebo jiný OS (ne debian), měli byste hledat umístění souboru v dokumentaci nebo jej zadat ručně.

Zkusme zvážit konfiguraci podrobněji.

Přechod na UNIX sockety

Pravděpodobně první věc, kterou byste měli věnovat pozornost, je to, jak data přecházejí z webového serveru do vašich php procesů. To se odráží v direktivě listen:

poslech = 127.0.0.1:9000

Pokud je nastavena adresa:port, pak data procházejí zásobníkem TCP a to pravděpodobně není příliš dobré. Pokud existuje cesta k soketu, například:

listen = /var/run/php5-fpm.sock

pak data procházejí unixovým socketem a tuto sekci můžete přeskočit.

Proč se stále vyplatí přejít na unixovou patici? UDS (unix domain socket), na rozdíl od komunikace přes TCP stack, má významné výhody:

  • nevyžadují přepínání kontextu, UDS používá netisr)
  • Datagram UDS zapsaný přímo do cílového soketu
  • odeslání datagramu UDS vyžaduje méně operací (žádné kontrolní součty, žádné hlavičky TCP, žádné směrování)

Průměrná latence TCP: 6 us Průměrná latence UDS: 2 us Průměrná latence PIPE: 2 us Průměrná propustnost TCP: 253702 msg/s Průměrná propustnost UDS: 1733874 PIPE Průměrná propustnost: 1682796 msg/s

UDS má tedy zpoždění ~66% méně a propustnost v 7krát více TCP. Proto se s největší pravděpodobností vyplatí přejít na UDS. V mém případě bude soket umístěn na /var/run/php5-fpm.sock .

; komentujte to - poslouchejte = 127.0.0.1:9000 poslouchejte = /var/run/php5-fpm.sock

Měli byste se také ujistit, že webový server (nebo jakýkoli jiný proces, který potřebuje komunikovat) má přístup pro čtení/zápis do vašeho soketu. K tomu existují nastavení. poslouchat.skupinu a režim poslechu Nejjednodušší způsob je spustit oba procesy od stejného uživatele nebo skupiny, v našem případě php-fpm a webový server se spustí se skupinou www-data:

listen.owner=www-data listen.group=www-data listen.mode=0660

Kontrola vybraného mechanismu zpracování událostí

Pro efektivní práci s I/O (vstup-výstup, soubor / zařízení / deskriptory soketu) se vyplatí zkontrolovat, zda je nastavení správné události.mechanismus. Pokud je php-fpm nainstalováno ze systémového úložiště, s největší pravděpodobností je tam vše v pořádku - buď není zadáno (instalováno automaticky), nebo zadáno správně.

Jeho význam závisí na OS, pro který je v dokumentaci nápověda:

; - epoll (linux >= 2.5.44); - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) ; - /dev/poll (Solaris >= 7) ; - port (Solaris >= 10)

Pokud například pracujeme na moderní linuxové distribuci, potřebujeme epool:

události.mechanismus = epoll

Výběr typu bazénu - dynamický / statický / na vyžádání

Také byste měli věnovat pozornost nastavení správce procesů (pm). Ve skutečnosti se jedná o hlavní proces (master proces), který bude řídit všechny podřízené (které spouštějí kód aplikace) podle určité logiky, která je ve skutečnosti popsána v konfiguračním souboru.

K dispozici jsou celkem 3 schémata řízení procesů:

  • dynamický
  • statický
  • na požádání

Nejjednodušší je statický. Schéma jeho práce je následující: spouštět pevný počet podřízených procesů a udržovat je v chodu. Toto schéma práce není příliš efektivní, protože počet požadavků a jejich zatížení se mohou čas od času měnit, ale počet podřízených procesů nikoli - vždy zabírají určité množství paměti RAM a nemohou postupně zpracovávat špičkové zatížení.

dynamický pool tento problém vyřeší, reguluje počet podřízených procesů na základě hodnot konfiguračního souboru a mění je nahoru nebo dolů v závislosti na zatížení. Tento fond je nejvhodnější pro aplikační server, který potřebuje rychlou odpověď na požadavek, pracuje se špičkovým zatížením a vyžaduje úsporu prostředků (snížením počtu podřízených procesů při nečinnosti).

na požádání bazén je velmi podobný statický, ale při spuštění hlavního procesu nespustí podřízené procesy. Teprve když přijde první požadavek, vytvoří se první podřízený proces a po určité době (zadané v konfiguraci) bude zabit. Proto je relevantní pro servery s omezenými prostředky nebo logikou, která nevyžaduje rychlou odezvu.

Úniky paměti a zabiják OOM

Měli byste věnovat pozornost kvalitě aplikací, které budou spouštěny podřízenými procesy. Pokud kvalita aplikace není příliš vysoká nebo se používá mnoho knihoven třetích stran, musíte přemýšlet o možných únikech paměti a nastavit hodnoty na tyto proměnné:

  • pm.max_requests
  • request_terminate_timeout

pm.max_requests toto je maximální počet požadavků, které podřízený proces zpracuje, než bude zabit. Násilným zabitím procesu se vyhnete situaci, kdy se paměť podřízeného procesu „nabobtná“ kvůli únikům (protože proces pokračuje v práci po požadavku po požadavku). Na druhou stranu příliš malá hodnota bude mít za následek časté restarty, což povede ke ztrátám výkonu. Vyplatí se začít s hodnotou 1000 a poté tuto hodnotu snížit nebo zvýšit.

request_terminate_timeout nastavuje maximální dobu, po kterou může podřízený proces běžet, než bude zabit. Tím se vyhnete dlouhým dotazům, pokud se z nějakého důvodu změnila hodnota max_execution_time v nastavení interpretu. Hodnota by měla být nastavena na základě logiky zpracovávaných aplikací, řekněme 60. léta(1 minuta).

Konfigurace dynamického fondu

Pro hlavní aplikační server je kvůli zjevným výhodám často zvolen dynamický fond. Jeho činnost je popsána následujícími nastaveními:

  • pm.max_children- maximální počet podřízených procesů
  • pm.start_servers- počet procesů při spuštění
  • pm.min_spare_servers- minimální počet procesů čekajících na připojení (požadavky na zpracování)
  • pm.max_spare_servers- maximální počet procesů čekajících na připojení (požadavek na zpracování)

Pro správné nastavení těchto hodnot je nutné zvážit:

  • kolik paměti průměrně spotřebuje dětský proces
  • dostupná RAM

Průměrnou hodnotu paměti na proces php-fpm na již běžící aplikaci můžete zjistit pomocí plánovače:

# ps -ylC php-fpm --sort:rss S UID PID PPID C PRI NI RSS SZ WCHAN TTY TIME CMD S 0 1445 1 0 80 0 9552 42588 ep_pol ? 00:00:00 php5-fpm

Potřebujeme průměrnou hodnotu ve sloupci RSS (velikost rezidentní paměti v kilobajtech). V mém případě je to ~20 Mb. V případě, že aplikace nezatěžují, můžete použít Apache Benchmark k vytvoření nejjednoduššího zatížení php-fpm.

Množství celkové / dostupné / použité paměti lze zobrazit pomocí volný, uvolnit:

# free -m celkem využito zdarma ... Paměť: 4096 600 3496

Celkový maximální počet procesů = (celkový počet RAM - (použitý RAM + vyrovnávací paměť)) / (paměť na proces php) Celková paměť RAM: 4 GB Použitá paměť RAM: 1000 MB bezpečnostní vyrovnávací paměť: 400 MB paměti na podřízený proces php-fpm (průměr): 30 MB Maximální možný počet procesy = (4096 - (1000 + 400)) / 30 = 89 Sudé číslo: 89 zaokrouhleno dolů na 80

Hodnotu zbývajících direktiv lze nastavit na základě očekávaného zatížení aplikace a také vzít v úvahu, co dalšího server dělá kromě php-fpm (řekněme, že DBMS také vyžaduje zdroje). Pokud je na serveru mnoho úloh, vyplatí se snížit počet počátečních i maximálních procesů.

Vezměme například v úvahu, že na serveru jsou 2 fondy www1 a www2 (například 2 webové zdroje), konfigurace každého z nich pak může vypadat takto:

pm.max_children = 40 ; 80 / 14 pm.start_servers = 15 pm.min_spare_servers = 15 pm.max_spare_servers = 25

1. GROUP BY one key

Tato funkce funguje jako GROUP BY pro pole, ale s jedním důležitým omezením: Je možný pouze jeden seskupovací "sloupec" ($identifikátor) ​​.

Funkce arrayUniqueByIdentifier(pole $pole, řetězec $identifikátor) ​​( $ids = pole_column($pole, $identifikátor); $ids = pole_unique($ids); $array = pole_filter($pole, funkce ($klíč, $hodnota ) use ($ids) ( return in_array($value, array_keys($ids)); ), ARRAY_FILTER_USE_BOTH); return $array; )

2. Detekce jedinečných řádků pro tabulku (dvourozměrné pole)

Tato funkce slouží k filtrování „řádků“. Řekneme-li, že dvourozměrné pole je tabulka, pak každý jeho prvek je řádek. Pomocí této funkce tedy můžeme odstranit duplicitní řádky. Dva řádky (prvky prvního rozměru) jsou stejné, pokud jsou všechny jejich sloupce (prvky druhého rozměru) stejné. Pro porovnávání "sloupcových" hodnot platí: Pokud je hodnota jednoduchého typu, použije se při porovnávání samotná hodnota; jinak bude použit jeho typ (pole , objekt , zdroj , neznámý typ).

Strategie je jednoduchá: Vytvořte z původního pole mělké pole, kde prvky jsou implodovány do "sloupců" původního pole; pak na něj aplikujte array_unique(...); a jako poslední použít zjištěná ID pro filtrování původního pole.

Funkce arrayUniqueByRow(pole $table = , řetězec $implodeSeparator) ( $elementStrings = ; foreach ($table as $row) ( // Chcete-li se vyhnout upozorněním jako "Převod pole na řetězec". $elementPreparedForImplode = array_map(funkce ($pole) ( $valueType = gettype($field); $simpleTypes = ["boolean", "integer", "double", "float", "string", "NULL"]; $field = in_array($valueType, $simpleTypes) ? $field: $valueType; return $field; ), $řádek); $elementStrings = implode($implodeSeparator, $elementPreparedForImplode); ) $elementStringsUnique = array_unique($elementStrings); $table = array_intersect_key($table, $elementStringsUnique); vrátit $table ;)

Je také možné zlepšit porovnávání, detekovat třídu hodnoty "sloupce", pokud je jejím typem objekt.

$implodeSeparator by měl být víceméně komplexní, z.B. spl_object_hash($this) .

3. Detekce řádků se sloupci s jedinečným identifikátorem pro tabulku (dvourozměrné pole)

Toto řešení se opírá o 2. Nyní nemusí být celý „řádek“ jedinečný. Dva „řádky“ (prvky první dimenze) jsou nyní stejné, pokud všechny relevantní"pole" (prvky druhé dimenze) jednoho "řádku" se rovnají odpovídajícím "polím" (prvkům se stejným klíčem).

"Relevantní" "pole" jsou "pole" (prvky druhé dimenze), které mají klíč, který se rovná jednomu z prvků předávaných "identifikátorů".

Funkce arrayUniqueByMultipleIdentifiers(pole $tabulka, pole $identifikátory, řetězec $implodeSeparator = null) ( $arrayForMakingUniqueByRow = $removeArrayColumns($table, $identifiers, true); $arrayUniqueByRow = $arrayUniqueByult_ByRayByRowse = $arrayUniqueByult_Row_RowniqueSeparator = pole ($table, $arrayUniqueByRow); return $arrayUniqueByMultipleIdentifiers; ) function removeArrayColumns(pole $table, pole $columnNames, bool $isWhitelist = false) (foreach ($table as $rowKey => $row) ( if (is_array( $row )) ( if ($isWhitelist) ( foreach ($row as $fieldName => $fieldValue) (neif (!in_array($fieldName, $columnNames)) ( unset($table[$rowKey][$fieldName ]); ) ) ) else ( foreach ($row as $fieldName => $fieldValue) ( ​​​if (in_array($fieldName, $columnNames)) ( unset($table[$rowKey][$fieldName]); ) ) ) ) ) vrátit $ tabulku; )

Vzhledem k tomu, že vývoj technologií vedl k tomu, že každý programátor má nyní svůj vlastní počítač, jako vedlejší efekt máme tisíce různých knihoven, frameworků, služeb, API atd. pro všechny příležitosti. Když ale přijde tento případ života, vyvstává problém – na co je použít a co dělat, když to úplně nesedí – přepsat, napsat vlastní od začátku nebo našroubovat několik řešení pro různé případy použití.

Myslím, že mnozí si všimli, že tvorba projektu často nespočívá ani tak v programování, jako spíše v psaní kódu pro integraci několika hotových řešení. Někdy se takové kombinace promění v nová řešení, která lze opakovaně použít v následných problémech.

Přejděme ke konkrétní „běžící“ úloze – objektové vrstvě pro práci s databázemi v PHP. Existuje spousta řešení, od PDO po víceúrovňové (a podle mého názoru v PHP ne zcela vhodné) ORM motory.

Většina těchto řešení migrovala na PHP z jiných platforem. Často ale autoři neberou v úvahu vlastnosti PHP, které by značně zjednodušilo jak psaní, tak používání portable konstruktů.
Jednou z běžných architektur pro tuto třídu úloh je vzor Active Record. Podle tohoto vzoru jsou vytvořeny zejména takzvané entity, které se v té či oné podobě používají na řadě platforem, od perzistentních beanů v EJB3 po EF v .NET.

Vytvořme tedy podobnou konstrukci pro PHP. Spojme dvě super věci – hotovou knihovnu ADODB a slabě typované a dynamické vlastnosti objektů v jazyce PHP.
Jednou z mnoha funkcí ADODB je tzv. automatické generování SQL dotazů pro vkládání (INSERT) a aktualizaci (UPDATE) záznamů na základě asociativních polí s daty.
Ve skutečnosti není nic vojenského, co by si vzalo pole, kde klíče jsou názvy polí a hodnoty jsou data a generují řetězec dotazu SQL. Ale ADODB to dělá inteligentněji. Dotaz je postaven na základě struktury tabulky, která je předběžně načtena z databázového schématu. Výsledkem je, že za prvé se do sql dostanou pouze existující pole a ne vše v řadě a za druhé se zohlední typ pole - u řetězců jsou přidány uvozovky, formáty data lze tvořit na základě časového razítka, pokud to ADODB vidí místo řetězce v přenášené hodnotě atd. .

Nyní pojďme ze strany PHP.
Představte si takovou třídu (zjednodušeně).

Entita třídy( chráněné $pole = pole(); veřejná konečná funkce __set($jméno, $hodnota) ( ​​$this->pole[$jméno] = $hodnota; ) veřejná konečná funkce __get($jméno) ( return $ this- >fields[$name]; ) )

Předáním interního pole do knihovny ADODB můžeme automaticky generovat SQL dotazy pro aktualizaci záznamu v databázi tímto objektem.Současně těžkopádné konstrukce mapování polí databázových tabulek na pole objektu entity na bázi XML a podobné nejsou potřeba. Je pouze nutné, aby název pole odpovídal vlastnosti objektu. Protože na způsobu pojmenování polí v databázi a polí objektu nezáleží pro počítač, není důvod, aby se neshodovaly.

Pojďme si ukázat, jak to funguje ve finální verzi.
Kód pro dokončenou třídu se nachází na Gist . Jedná se o abstraktní třídu, která obsahuje minimum nutné pro práci s databází. Podotýkám, že tato třída je zjednodušenou verzí řešení vypracovanou na několika desítkách projektů.

Představme si, že máme takovou tabulku:

CREATE TABLE `users` (`username` varchar(255) , `created` date , `user_id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`user_id`))
Na typu databáze nezáleží – ADODB poskytuje přenositelnost pro všechny běžné databázové servery.

Vytvořme třídu entity User, založenou na třídě Entity

/** * @table=users * @keyfield=user_id */ class User extends Entity()

To je vlastně všechno.
Používá se jednoduše:

$user = new User(); $user->username="Vasya Pupkin"; $user->created=time(); $user->save(); //uložit do úložiště //načíst znovu $thesameuser = User::load($user->user_id); echo $thesameuser ->uživatelské jméno;

Tabulku a pole klíče specifikujeme v pseudoanotacích.
Můžeme také určit pohled (například view =usersview), pokud, jak je tomu často, je entita vybrána na základě její tabulky s připojenými nebo vypočítanými poli. V tomto případě budou data vybrána z pohledu a tabulka bude aktualizována. Ti, kterým se takové poznámky nelíbí, mohou přepsat metodu getMetatada() a zadat parametry tabulky ve vráceném poli.

Co dalšího je užitečné na třídě Entity v této implementaci?

Můžeme například přepsat metodu init(), která se volá po vytvoření instance entity, a inicializovat výchozí datum vytvoření.
Nebo přetížit metodu afterLoad(), která je automaticky volána po načtení entity z databáze, a převést datum na časové razítko pro další pohodlnější použití.
Ve výsledku tak získáme ne o moc složitější strukturu.

/** * @table=users * @view=usersview * @keyfield=user_id */ class Uživatel rozšiřuje Entitu( chráněná funkce init() ( $this->created = time(); ) chráněná funkce afterLoad() ( $this ->created = strtotime($this->created); ) )

Můžete také přetížit metody beforeSave a beforeDelete a další události životního cyklu, kde můžete například provést ověření před uložením nebo některé další akce - například odstranit obrázky z nahrávání, když je uživatel smazán.

Načteme seznam entit podle kritéria (ve skutečnosti podmínek pro KDE).
$users = User::load("uživatelské jméno jako "Pupkin" ");
Třída Entity také umožňuje provádět libovolný, „nativní“ SQL dotaz, abych tak řekl. Chceme například vrátit seznam uživatelů s nějakými seskupeními podle statistik. Nezáleží na tom, která konkrétní pole budou vrácena (hlavní je, že existuje user_id, pokud je potřeba s entitou dále manipulovat), stačí znát jejich jména, abyste měli přístup k vybraným polím. Při ukládání entity, jak je z výše uvedeného zřejmé, také není nutné vyplňovat všechna pole, která budou v objektu entity přítomna, jdou do databáze. To znamená, že nepotřebujeme vytvářet další třídy pro libovolný výběr. Přibližně jako anonymní struktury při načítání v EF, pouze zde je to stejná třída entity se všemi metodami obchodní logiky.

Přísně vzato, výše uvedené metody získávání seznamů jsou poněkud mimo vzor AR. V podstatě jsou to tovární metody. Ale jak starý muž z Ockhamu odkázal, nebudeme produkovat entity nad rámec toho, co je nutné, a ohradit samostatného Entity Managera nebo něco takového.

Všimněte si, že výše uvedené jsou pouze třídy PHP a lze je rozšiřovat a upravovat, jak chcete, přidáním vlastností a metod obchodní logiky do entity (nebo do základní třídy Entity). To znamená, že nezískáme jen kopii řádku databázové tabulky, ale obchodní entitu jako součást objektové architektury aplikace.

Kdo z toho může mít prospěch? Samozřejmě ne pro vývojáře, kteří nejsou napumpovaní, kteří věří, že používat něco jednoduššího, než je doktrína, není solidní, a ne pro perfekcionisty, kteří si jsou jisti, že pokud řešení nevytáhne miliardu DB přístupů za sekundu, pak je to není řešení. Soudě podle fór, mnoho běžných vývojářů pracujících na běžných (z toho 99,9 %) projektů dříve či později čelí problému najít jednoduchý a pohodlný objektový způsob přístupu k databázi. Potýkají se však s tím, že většina řešení je buď nepřiměřeně vymyšlená, nebo jsou součástí rámce.

P.S. Učinil rozhodnutí z rámce jako samostatný projekt