Ако сте разработвали PHP през последните няколко години, вероятно сте наясно с проблемите на този език. Често можете да чуете, че това е фрагментиран език, инструмент за хакване, че няма реална спецификация и т.н. Реалността е, че PHP нарасна много в последно време. Версията на PHP 5.4 го доближи до завършване обектен модели предостави много нови функции.

И всичко това, разбира се, е добре, но какво да кажем за рамките? Има много от тях в PHP. Трябва само да започнете да търсите и ще разберете, че няма да имате достатъчно живот, за да ги изучавате всички, защото постоянно се появяват нови рамки и във всяка се измисля нещо свое. И така, как да превърнете това в нещо, което не отчуждава разработчиците и улеснява пренасянето на функционалност от една рамка в друга?

Какво е PHPFIG

PHP-FIG (PHP Framework Interop Group) е организирана група от разработчици, чиято цел е да намерят начини няколко рамки да работят заедно.

Само си представете: в момента поддържате проект на Zend Framework, който се нуждае от модул за пазарска количка. Вече сте написали такъв модул за предишен проект, който беше на Symphony. Защо не го направиш отново? За щастие и ZendF, и Symphony са част от PHP-FIG, така че е възможно да импортирате модул от една рамка в друга. Не е ли страхотно?

Нека разберем какви рамки са включени в PHP-FIG

Членове на PHP-FIG

Всеки разработчик може да добави своята рамка към списъка с участници в PHP-FIG. За това обаче ще трябва да платите определена сума, така че ако нямате подкрепата на общността, едва ли ще се съгласите с това. Това е, за да се попречи на милиони микрорамки да се регистрират без никаква репутация.

Настоящи членове:

Какво е PSR?

PSR (PHP Standards Recommendations) - стандартни препоръки, резултат от PHP-FIG. Някои членове на групата предлагат правила за всеки PSR, други гласуват в подкрепа на тези правила или за тяхното премахване. Дискусията се провежда в Google Groups, а PSR комплектите са достъпни на официалния уебсайт на PHP-FIG.

Нека да разгледаме някои PSR:

Първата стъпка към обединяване на рамките е да имате обща структура на директория, поради което е приет общ стандарт за автоматично зареждане.

  1. Пространството от имена (именно пространство) и класът трябва да имат структурата \\(\)*.
  2. Всяко пространство от имена трябва да съдържа пространство от най-високо ниво („Име на доставчик“).
  3. Всяко пространство от имена може да има произволен брой нива.
  4. Всеки разделител на пространство от имена се преобразува в DIRECTORY_SEPARATOR при зареждане.
  5. Всеки знак "_" в CLASS NAME се преобразува в DIRECTORY_SEPARATOR.
  6. Напълно квалифицираното пространство от имена и клас се добавят с ".php" при зареждане.

Пример за функция за автоматично зареждане:

PSR-1 - Основен стандарт за кодиране

Тези PSR регулират основните стандарти, чиято основна идея е, че ако всички разработчици използват едни и същи стандарти, тогава пренасянето на код може да се извърши без никакви проблеми.

  1. Файловете трябва да използват само тагове
  2. Файловете трябва да използват само UTF-8 без BOM кодиране.
  3. Имената и класовете на пространствата трябва да следват PSR-0.
  4. Имената на класовете трябва да бъдат декларирани в нотация StudlyCaps.
  5. Константите на класа трябва да бъдат декларирани с главни букви, разделени с долна черта.
  6. Методите трябва да бъдат декларирани в нотация camelCase.

PSR-2 - Ръководство за стил на кодиране

Това са разширени инструкции за PSR-1, описващи правилата за форматиране на кода.

  1. Кодът трябва да отговаря на PSR-1.
  2. Вместо табулатори трябва да се използват 4 интервала.
  3. Не трябва да има строго ограничение за дължината на низа, препоръчителната дължина е до 80 знака.
  4. Трябва да има един празен ред след декларацията на пространството от имена.
  5. Скобите за класове трябва да се отварят на следващия ред след декларацията и да се затварят след тялото на класа (същото за методите).
  6. Видимостта на методите и свойствата трябва да бъде дефинирана (публична, частна).
  7. Отварящите скоби за контролните структури трябва да са на същия ред, затварящите скоби трябва да са на следващия ред след тялото на структурата.
  8. Не се поставят интервали след отварящите скоби на методите на контролната структура и преди затварящите скоби.

PCR-3 - Интерфейс за регистратор

PCR-3 регулира сечта, по-специално основните девет метода.

  1. LoggerInterface предоставя 8 метода за регистриране на осем нива на RFC 5424 (отстраняване на грешки, известие, предупреждение, грешка, критично, предупреждение, спешно).
  2. Деветият метод log() приема нивото на предупреждение като първи параметър. Извикването на метод с параметър за ниво на предупреждение трябва да върне същия резултат като извикването на метод на конкретно ниво на журнал (log(ALERT) == alert()). Извикването на метод с недефинирано ниво на предупреждение трябва да генерира Psr\Log\InvalidArgumentException.

Подобно на PSR-0, PSR-4 предоставя подобрени методи за автоматично зареждане

  1. Терминът "клас" се отнася до класове, интерфейси, характеристики и други подобни структури.
  2. Напълно квалифицирано име на клас има следната форма: \ (\)*\
  3. Когато зареждате файл, който съответства на напълно квалифицирано име на клас:
  • Непрекъсната поредица от едно или повече водещи пространства от имена, с изключение на водещия разделител на пространство от имена, в напълно квалифицирано име на клас съответства на поне една „главна директория“.
  • Имената на директориите и поддиректориите трябва да съответстват на регистъра на буквите в пространството от имена.
  • Окончанието на пълното име на класа съответства на името на файла с окончание .php. Регистърът на името на файла трябва да съответства на регистъра на края на пълното име на класа.
  • Реализацията на автоматично зареждане не трябва да хвърля изключения, да генерира грешки от каквото и да е ниво и не трябва да връща стойност.

Заключение

PHP-FIG променя начина, по който са написани рамките, но не и как работят. Клиентите често изискват да работите със съществуващ код в рамка или да посочите с коя рамка трябва да работите по даден проект. PSR препоръките правят живота много по-лесен за разработчиците в това отношение, което е страхотно!

PHP език за програмиранеизмина дълъг път от инструмент за създаване на лични страници до език с общо предназначение. Днес той е инсталиран на милиони сървъри по целия свят, използван от милиони разработчици, които създават голямо разнообразие от проекти.

Лесен е за научаване и изключително популярен, особено сред начинаещите. Следователно след развитието на езика последва мощно развитие на общността около него. Огромен брой скриптове, за всички случаи, различни библиотеки, рамки. Липсата на единни стандарти за дизайн и кодиране доведе до появата на огромен слой от информационни продукти, изградени върху собствените принципи на разработчика на този продукт. Това беше особено забележимо при работа с различни PHP рамки, които дълго време представляваха затворена екосистема, несъвместима с други рамки, въпреки факта, че задачите, които решават, често са сходни.

През 2009 г. разработчиците на няколко рамки се съгласиха да създадат общност PHP Framework Interop Group (PHP-FIG), който ще разработи препоръки за разработчиците. Важно е да подчертаем, че не говорим за ISO стандарти, по-правилно е да говорим за препоръки. Но тъй като тези, които са създали php-фигобщността на разработчиците представляват основни рамки, техните препоръки имат сериозна тежест. поддържа PSR (PHP стандартна препоръка) стандартипозволява оперативна съвместимост, което улеснява и ускорява разработването на крайния продукт.

Общо към момента на писане има 17 стандарта, като 9 от тях са одобрени, 8 са в етап на проект, активно се обсъждат, 1 стандарт не се препоръчва за употреба.

Сега нека преминем директно към описанието на всеки стандарт. Имайте предвид, че тук няма да разглеждам подробно всеки стандарт, а по-скоро малко въведение. Освен това статията ще разгледа само тези PSR стандарти, които са официално приети, т.е. са в състояние Прието.

PSR-1. Основен стандарт за кодиране

Той представлява най-общите правила, като например използването PHP тагове, кодиране на файлове, разделяне на мястото на декларация на функция, клас и място на тяхното използване, именуване на класове, методи.

PSR-2. Ръководство за стил на код

Той е продължение на първия стандарт и регулира използването на табулатори в кода, прекъсване на редове, максимална дължина на кодовите редове, правилата за проектиране на контролни структури и др.

PSR-3. Интерфейс за регистриране.

Този стандарт е предназначен да позволи (регистриране) регистриране в приложения, написани в PHP.

PSR-4. Стандартно автоматично зареждане

Това е може би най-важният и необходим стандарт, който ще бъде разгледан в отделна, подробна статия. Класове, които изпълняват PSR-4, може да се зареди с един автоматичен зареждащ механизъм, което позволява части и компоненти от една рамка или библиотека да се използват в други проекти.

PSR-6. интерфейс за кеширане

Кеширането се използва за подобряване на производителността на системата. И PSR-6позволява стандартно записване и извличане на данни от кеша чрез унифициран интерфейс.

PSR-7. HTTP интерфейс за съобщения

Когато пишете повече или по-малко сложно сайтове в PHP, почти винаги трябва да се работи с HTTP заглавки. Разбира се, PHP езикни предоставя готови варианти за работа с тях, като напр суперглобален масив $_SERVER, функции заглавка (), setcookie()и т.н., но техният ръчен анализ е изпълнен с грешки и не винаги е възможно да се вземат предвид всички нюанси на работа с тях. И така, за да се улесни работата на разработчика, както и да се направи интерфейсът за взаимодействие с HTTP протоколтози стандарт е приет. Ще говоря за този стандарт по-подробно в една от следващите статии.

PSR-11. Интерфейс на контейнера

При писане PHP програмиЧесто трябва да използвате компоненти на трети страни. И за да не се изгубите в тази гора от зависимости, бяха измислени различни методи за управление на зависимостите на кода, често несъвместими един с друг, които този стандарт води до общ знаменател.

PSR-13. Хипермедийни връзки

Този интерфейс е предназначен да улесни разработването и използването на интерфейси за програмиране на приложения ( API).

PSR-14. Опростен интерфейс за кеширане

Това е продължение и подобрение на стандарта PSR-6

Така днес разгледахме PSR стандарти. За актуална информация относно състоянието на стандартите, моля свържете се с

16.09.2016

Нека се опитаме да определим как да подобрим производителността на сървъра за приложения, базиран на php-fpm, както и да създадем контролен списък за проверка на fpm конфигурацията на процеса.

На първо място, струва си да се определи местоположението на конфигурационния файл на пула. Ако сте инсталирали php-fpm от системното хранилище, тогава конфигурацията на пула wwwще се намира около /etc/php5/fpm/pool.d/www.conf. Ако използвате собствена компилация или друга операционна система (не debian), трябва да потърсите местоположението на файла в документацията или да го посочите ръчно.

Нека се опитаме да разгледаме конфигурацията по-подробно.

Преминаване към UNIX сокети

Вероятно първото нещо, на което трябва да обърнете внимание, е как данните преминават от уеб сървъра към вашите php процеси. Това е отразено в директивата за слушане:

слушам = 127.0.0.1:9000

Ако е зададен адрес:порт, тогава данните преминават през TCP стека и това вероятно не е много добре. Ако има път към гнездото, например:

слушам = /var/run/php5-fpm.sock

след това данните преминават през unix сокета и можете да пропуснете този раздел.

Защо все още си струва да преминете към unix сокет? UDS (unix domain socket), за разлика от комуникацията през TCP стека, има значителни предимства:

  • не изисква превключване на контекста, UDS използва netisr)
  • UDS дейтаграма, записана директно в целевия сокет
  • изпращането на UDS дейтаграма изисква по-малко операции (без контролни суми, без TCP заглавки, без маршрутизиране)

TCP Средна латентност: 6 us UDS Средна латентност: 2 us PIPE Средна латентност: 2 us TCP Средна пропускателна способност: 253702 msg/s UDS Средна пропускателна способност: 1733874 msg/s PIPE Средна пропускателна способност: 1682796 msg/s

По този начин UDS има забавяне от ~66% по-малкои пропускателна способност в 7 пъти повече TCP. Следователно най-вероятно си струва да преминете към UDS. В моя случай сокетът ще се намира в /var/run/php5-fpm.sock.

; коментирайте го - слушайте = 127.0.0.1:9000 слушайте = /var/run/php5-fpm.sock

Трябва също така да се уверите, че уеб сървърът (или всеки друг процес, който трябва да комуникира) има достъп за четене/запис до вашия сокет. Има настройки за това. слушай.групаи режим на слушанеНай-лесният начин е да стартирате и двата процеса от един и същ потребител или група, в нашия случай php-fpm и уеб сървърът ще бъде стартиран с групата www-данни:

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

Проверка на избрания механизъм за обработка на събития

За да работите с ефективна работа с I / O (дескриптори на вход-изход, файл / устройство / сокет), си струва да проверите дали настройката е правилна събития.механизъм. Ако php-fpm е инсталиран от системното хранилище, най-вероятно там всичко е наред - или не е посочено (инсталира се автоматично), или е посочено правилно.

Значението му зависи от операционната система, за която има намек в документацията:

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

Например, ако работим върху модерна Linux дистрибуция, имаме нужда от epool:

събития.механизъм = epoll

Избор на тип пул - динамичен / статичен / по заявка

Също така трябва да обърнете внимание на настройките на мениджъра на процеси (pm). Всъщност това е основният процес (главен процес), който ще управлява всички дъщерни (които изпълняват кода на приложението) по определена логика, която всъщност е описана в конфигурационния файл.

Налични са общо 3 схеми за контрол на процеса:

  • динамичен
  • статичен
  • при поискване

Най-простият е статичен. Схемата на неговата работа е следната: стартирайте фиксиран брой дъщерни процеси и ги поддържайте работещи. Тази схема на работа не е много ефективна, тъй като броят на заявките и тяхното натоварване могат да се променят от време на време, но броят на дъщерните процеси не - те винаги заемат определено количество RAM и не могат да обработват пикови натоварвания на свой ред.

динамиченпулът ще реши този проблем, той регулира броя на дъщерните процеси въз основа на стойностите на конфигурационния файл, променяйки ги нагоре или надолу, в зависимост от натоварването. Този пул е най-подходящ за сървър на приложения, който се нуждае от бърз отговор на заявка, работи с пиково натоварване и изисква спестяване на ресурси (чрез намаляване на дъщерните процеси при неактивност).

при поискванебасейнът е много подобен на статичен, но не стартира дъщерни процеси, когато стартира главният процес. Само когато пристигне първата заявка, ще бъде създаден първият дъщерен процес и след определено време на изчакване (посочено в конфигурацията) той ще бъде убит. Следователно е подходящо за сървъри с ограничени ресурси или логика, която не изисква бърз отговор.

Изтичане на памет и OOM убиец

Трябва да обърнете внимание на качеството на приложенията, които ще се изпълняват от дъщерни процеси. Ако качеството на приложението не е много високо или се използват много библиотеки на трети страни, тогава трябва да помислите за възможни течове на памет и да зададете стойностите на такива променливи:

  • pm.max_requests
  • request_terminate_timeout

pm.max_requestsтова е максималният брой заявки, които дъщерният процес ще обработи, преди да бъде убит. Принудителното убиване на процес избягва ситуация, в която паметта на дъщерния процес "набъбва" поради течове (защото процесът продължава да работи след заявка след заявка). От друга страна, стойност, която е твърде малка, ще доведе до често рестартиране, което ще доведе до загуба на производителност. Струва си да започнете със стойност 1000 и след това да намалите или увеличите тази стойност.

request_terminate_timeoutзадава максималното време, което дъщерен процес може да работи, преди да бъде убит. Това избягва дългите заявки, ако по някаква причина стойността на max_execution_time в настройките на интерпретатора е променена. Стойността трябва да бъде зададена въз основа на логиката на обработваните приложения, да речем 60-те години(1 минута).

Конфигуриране на динамичен пул

За основен сървър на приложения, поради очевидните предимства, често се избира динамичният пул. Работата му се описва от следните настройки:

  • pm.max_children- максимален брой дъщерни процеси
  • pm.start_servers- брой процеси при стартиране
  • pm.min_spare_servers- минималният брой процеси, чакащи връзка (заявки за обработка)
  • pm.max_spare_servers- максималният брой процеси, чакащи връзка (заявки за обработка)

За да зададете правилно тези стойности, е необходимо да вземете предвид:

  • колко памет консумира средно дъщерен процес
  • налична RAM памет

Можете да разберете средната стойност на паметта за php-fpm процес на вече работещо приложение с помощта на планировчика:

# 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

Нуждаем се от средната стойност в колоната RSS (размер на резидентната памет в килобайти). В моя случай е ~20Mb. В случай, че няма натоварване на приложенията, можете да използвате Apache Benchmark, за да създадете най-простото натоварване на php-fpm.

Количеството обща / налична / използвана памет може да се види с Безплатно:

# безплатно -m общо използвани безплатни ... Памет: 4096 600 3496

Общо макс. процеси = (Общо RAM - (Използвана RAM + буфер)) / (Памет на php процес) Общо RAM: 4GB Използвана RAM: 1000MB Буфер за сигурност: 400MB Памет на дъщерен php-fpm процес (средно): 30MB Максимален възможен брой процеси = (4096 - (1000 + 400)) / 30 = 89 Четно число: 89 закръглено надолу до 80

Стойността на останалите директиви може да бъде зададена въз основа на очакваното натоварване на приложението и също така да вземе предвид какво друго прави сървърът освен php-fpm (да речем, СУБД също изисква ресурси). Ако има много задачи на сървъра, струва си да намалите броя на първоначалните / максималните процеси.

Например, нека вземем предвид, че на сървъра има 2 пула www1 и www2 (например 2 уеб ресурса), тогава конфигурацията на всеки от тях може да изглежда така:

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

1. ГРУПИРАНЕ ПО един ключ

Тази функция работи като GROUP BY за масив, но с едно важно ограничение: Възможна е само една „колона“ за групиране ($identifier).

Функция arrayUniqueByIdentifier(масив $масив, низ $идентификатор)​($ids = array_column($масив, $идентификатор); $ids = array_unique($ids); $масив = array_filter($масив, функция ($key, $value) ) използвайте ($ids) ( return in_array($value, array_keys($ids)); ), ARRAY_FILTER_USE_BOTH); return $array; )

2. Откриване на уникалните редове за таблица (двуизмерен масив)

Тази функция е за филтриране на "редове". Ако кажем, че двумерният масив е таблица, тогава всеки негов елемент е ред. Така че можем да премахнем дублиращите се редове с тази функция. Два реда (елементи от първото измерение) са равни, ако всичките им колони (елементи от второто измерение) са равни. За сравняването на стойности в "колона" се прилага: Ако дадена стойност е от прост тип, самата стойност ще се използва при сравняване; в противен случай ще се използва неговият тип (масив, обект, ресурс, неизвестен тип).

Стратегията е проста: Направете от оригиналния масив плитък масив, където елементите са имплодирани d "колони" на оригиналния масив; след това приложете array_unique(...) върху него; и като последно използвайте откритите идентификатори за филтриране на оригиналния масив.

Функция arrayUniqueByRow(array $table = , string $implodeSeparator) ( $elementStrings = ; foreach ($table as $row) ( // За да избегнете забележки като „преобразуване на масив в низ“. $elementPreparedForImplode = array_map(function ($field) ( $valueType = gettype($field); $simpleTypes = ["boolean", "integer", "double", "float", "string", "NULL"]; $field = in_array($valueType, $simpleTypes)? $field: $valueType; return $field; ), $row); $elementStrings = implode($implodeSeparator, $elementPreparedForImplode); ) $elementStringsUnique = array_unique($elementStrings); $table = array_intersect_key($table, $elementStringsUnique); върне $table; )

Също така е възможно да се подобри сравнението, откривайки класа на стойността на "колона", ако типът му е обект.

$implodeSeparator трябва да е повече или по-малко сложен, например. spl_object_hash($this) .

3. Откриване на редове с уникален идентификатор на колони за таблица (двуизмерен масив)

Това решение разчита на второто. Сега не е необходимо целият "ред" да бъде уникален. Два "реда" (елементи от първото измерение) са равни сега, ако всички релевантни"полета" (елементи от второто измерение) на единия "ред" са равни на съответните "полета" (елементи със същия ключ).

„Релевантните“ „полета“ са „полетата“ (елементи от второто измерение), които имат ключ, който е равен на един от елементите на предадените „идентификатори“.

Функция arrayuniqueByMultipleIdentifiers (масив $ таблица, масив $ идентификатори, низ $ implodeseparator = null) ($ arrayformakinguniqueByrow = $ removearraycolumns ($ таблица, $ идентификатори, true); $ arrayuniqueByrow = $ arrayuniquebyrow ($ arrayformakeUniqueByrowrow, $ improdeseparator); = масив ($table, $arrayUniqueByRow); return $arrayUniqueByMultipleIdentifiers; ) function removeArrayColumns(array $table, array $columnNames, bool $isWhitelist = false) ( foreach ($table as $rowKey => $row) ( if (is_array( $row )) ( if ($isWhitelist) ( foreach ($row as $fieldName => $fieldValue) ( ​​​​if (!in_array($fieldName, $columnNames)) ( unset($table[$rowKey][$fieldName) ]); ) ) ) else ( foreach ($row as $fieldName => $fieldValue) ( ​​​​if (in_array($fieldName, $columnNames)) ( unset($table[$rowKey][$fieldName]); ) ) ) ) ) върне $ таблица; )

Тъй като развитието на технологиите доведе до факта, че всеки програмист вече има свой собствен компютър, като страничен ефект имаме хиляди различни библиотеки, рамки, услуги, API и т.н. за всякакви поводи. Но когато дойде този случай от живота, възниква проблемът - за какво да ги използвате и какво да направите, ако не пасва съвсем - пренапишете, напишете свои собствени от нулата или завийте няколко решения за различни случаи на употреба.

Мисля, че мнозина са забелязали, че често създаването на проект се свежда не толкова до програмиране, колкото до писане на код за интегриране на няколко готови решения. Понякога такива комбинации се превръщат в нови решения, които могат да се използват многократно в последващи проблеми.

Нека да преминем към конкретна "течаща" задача - обектен слой за работа с бази данни в PHP. Има много решения, вариращи от PDO до многостепенни (и, според мен, не съвсем подходящи в PHP) ORM двигатели.

Повечето от тези решения са мигрирали към PHP от други платформи. Но често авторите не вземат предвид характеристиките на PHP, което значително би опростило писането и използването на преносими конструкции.
Една от често срещаните архитектури за този клас задачи е моделът Active Record. По-специално, така наречените Entities са изградени според този модел, които се използват под една или друга форма в редица платформи, вариращи от постоянни beans в EJB3 до EF в .NET.

И така, нека изградим подобна конструкция за PHP. Нека съчетаем две готини неща - готовата ADODB библиотека и слабо типизираните и динамични свойства на обектите в PHP езика.
Една от многото функции на ADODB е така нареченото автоматично генериране на SQL заявки за вмъкване (INSERT) и актуализиране (UPDATE) на записи на базата на асоциативни масиви с данни.
Всъщност няма нищо военно, което да вземе масив, където ключовете са имената на полетата, а стойностите са съответно данните и генерират SQL низ за заявка. Но ADODB го прави по-интелигентно. Заявката се изгражда на базата на структурата на таблицата, която предварително се чете от схемата на базата данни. В резултат на това, първо, само съществуващи полета влизат в sql, а не всичко подред, и второ, типът на полето се взема предвид - добавят се кавички за низове, форматите на датата могат да се формират въз основа на клеймо за време, ако ADODB го види вместо низ в предаваната стойност и т.н.

Сега да преминем от страна на PHP.
Представете си такъв клас (опростен).

Class Entity( protected $fields = array(); public final function __set($name, $value) ( ​​​​$this->fields[$name] = $value; ) public final function __get($name) ( return $ това- >полета[$име]; ) )

Чрез предаване на вътрешния масив към библиотеката ADODB, можем автоматично да генерираме SQL заявки за актуализиране на запис в базата данни с този обект.В същото време тромавите конструкции на картографиране на полета на таблици на база данни към полета на обект на обект, базиран на XML и подобни не са необходими. Необходимо е само името на полето да съответства на свойството на обекта. Тъй като начинът, по който са именувани полетата в базата данни и полетата на обекта, няма значение за компютъра, няма причина те да не съвпадат.

Нека покажем как работи във финалната версия.
Кодът за завършен клас се намира на Gist. Това е абстрактен клас, който съдържа необходимия минимум за работа с базата данни. Отбелязвам, че този клас е опростена версия на решението, разработено върху няколко десетки проекта.

Нека си представим, че имаме таблица като тази:

CREATE TABLE `users` (`username` varchar(255), `created` date, `user_id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`user_id`))
Типът база данни няма значение - ADODB осигурява преносимост за всички често срещани сървъри на бази данни.

Нека създадем клас обект User, базиран на класа Entity

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

Всъщност това е всичко.
Използва се просто:

$потребител = нов потребител(); $user->username="Вася Пъпкин"; $user->created=time(); $user->save(); //запазване в хранилище //зареждане отново $thesameuser = User::load($user->user_id); echo $thesameuser ->потребителско име;

Посочваме таблицата и ключовото поле в псевдоанотации.
Можем също да посочим изглед (например изглед =usersview), ако, както често се случва, обектът е избран въз основа на неговата таблица с прикачени или изчислени полета. В този случай данните ще бъдат избрани от изгледа и таблицата ще бъде актуализирана. Тези, които не харесват подобни анотации, могат да заменят метода getMetatada() и да посочат параметрите на таблицата в върнатия масив.

Какво друго е полезно за класа Entity в тази реализация?

Например, можем да заменим метода init(), който се извиква след създаването на екземпляр на Entity, за да инициализираме датата на създаване по подразбиране.
Или претоварете метода afterLoad(), който се извиква автоматично, след като обектът бъде зареден от базата данни, за да преобразувате датата в клеймо за време за по-нататъшно по-удобно използване.
В резултат на това получаваме не много по-сложна структура.

/** * @table=users * @view=usersview * @keyfield=user_id */ class User extends Entity( protected function init() ( $this->created = time(); ) protected function afterLoad() ( $this ->created = strtotime($this->created); ) )

Можете също да претоварите методите beforeSave и beforeDelete и други събития от жизнения цикъл, където можете например да извършите проверка преди запазване или някои други действия - например премахване на изображения от качването, когато потребителят бъде изтрит.

Зареждаме списъка с обекти по критерия (всъщност условията за WHERE).
$users = User::load("потребителско име като "Pupkin" ");
Също така, класът Entity ви позволява да изпълните произволна, "родна" SQL заявка, така да се каже. Например, искаме да върнем списък с потребители с някои групи според статистиката. Няма значение кои конкретни полета ще бъдат върнати (основното е, че има user_id, ако има нужда от допълнителна манипулация на обекта), трябва само да знаете имената им, за да получите достъп до избраните полета. Когато записвате обект, както е очевидно от горното, също не е необходимо да попълвате всички полета, които ще присъстват в обекта на обекта, те ще отидат в базата данни. Тоест не е необходимо да създаваме допълнителни класове за произволни селекции. Приблизително като анонимни структури при извличане в EF, само че тук е един и същ клас обект с всички методи на бизнес логика.

Строго погледнато, горните методи за получаване на списъци са донякъде извън модела на AR. По принцип те са фабрични методи. Но както старецът на Окъм завеща, ние няма да произвеждаме субекти извън необходимото и да ограждаме отделен Entity Manager или нещо подобно.

Обърнете внимание, че горните са само PHP класове и могат да бъдат разширявани и модифицирани, както желаете, добавяйки свойства и методи на бизнес логиката към обекта (или основния клас Entity). Тоест получаваме не просто копие на ред от таблица на база данни, а бизнес обект като част от обектната архитектура на приложението.

Кой може да се възползва от това? Разбира се, не за разработчици, които не са напомпани, които вярват, че използването на нещо по-просто от доктрина не е солидно, и не за перфекционисти, които са сигурни, че ако едно решение не извлича милиард DB достъпа в секунда, тогава това е не е решение. Съдейки по форумите, много обикновени разработчици, работещи върху обикновени (от които 99,9%) проекти, рано или късно се сблъскват с проблема с намирането на прост и удобен обектен начин за достъп до базата данни. Но те са изправени пред факта, че повечето от решенията са или неоправдано натруфени, или са част от рамка.

P.S. Взе решение от рамката като отделен проект