Аспектно-орієнтована веб-розробка та PHP, PHP, Статті, Програмування - Програмування C,

Однак навіть тепер ми можемо знайти в коді наскрізну функціональність (crosscutting concerns), що бере участь у різних класах (протоколування, кешування, синхронізація, трасування, контроль безпеки, контроль транзакцій). Організувати подібну програмну логіку допоможе AOSD (Аспектно-орієнтована розробка програмного забезпечення).

Що таке AOSD?

Давайте представимо якийсь комплексний веб-додаток, наприклад, CMS, і розглянемо, на якому етапі і яким чином ми можемо зіткнутися із зазначеними проблемами. Припустимо, що з деякого числа функцій системи потрібно перетворення вхідних даних із XML на масиви. В даному випадку аспект XML-парсингу стосується лише невеликої кількості функцій і не передбачає суттєвого розвитку. Як бачимо, тут не потрібна розширена декомпозиція, немає очевидної необхідності використання AOSD. Логічніше визначити цю процедуру в метод кореневого класу (або зовнішнього класу, дивлячись за обставинами) і викликати його в міру необхідності.

аспектно-орієнтована

Малюнок 1.Прийнятна декомпозиція.

Однак якщо ж мова йде про моніторинг продуктивності, і наше завдання - на вимогу зняти свідчення з усіх функцій, що виконуються на їх входах і виходах, то навряд чи допоможуть які-небудь маніпуляції з об'єктами. Втім, скрупульозний читач запропонує скористатися попереднім прикладом у масштабі всього додатка і надалі використовувати тригер для включення та вимикання збору статистичних даних. Залишається його попередити, що коли раптом виникне необхідність задіяти протоколювання системних транзакцій для заданих випадків, при цьому підході доведеться згадувати всі деталі програмної архітектури тареорганізовувати її.

аспектно-орієнтована

Малюнок 2.Неприйнятна декомпозиція.

Наскільки було б зручніше попросити систему у межах певного аспекту належним чином обслужити задані події у певних об'єктах. Скажімо, минає час, і для нашого великого та складного проекту приходять нові вимоги щодо безпеки. Ми пишемо процедуру додаткових перевірок безпеки та вимагаємо від системи в рамках аспекту безпеки при викликі заданих методів виконувати цю процедуру. Парадигма аспектно-орієнтованої розробки програмного забезпечення має на увазі це. Ми виділяємо новий рівень абстракції поза існуючою програмною архітектурою і декларуємо в ньому функціональність, яка в тому чи іншому відношенні застосовується до системи в цілому. Як видно з малюнку 3, ми можемо виділити програмні процедури, які обслуговують систему, наприклад, у рамках аспекту безпеки та винести їх із основних класів. Далі ми можемо зробити те саме щодо процедур аспекту контролю вхідних даних. Таким чином, при кожному проході ми звільняємо бізнес-логіку системи, робимо її наочнішою. Фактично ми отримуємо в результаті наочну бізнес-логіку в основних класах системи та акуратно розфасовану наскрізну функціональність поза базовою моделлю.

аспектно-орієнтована

Малюнок 3.Аспектна декомпозиція.

  • Основа аспектно-орієнтованого підходу полягає в ідентифікації спільності програмного коду в рамках будь-яких аспектів та винесенні виділених процедур за межі основної бізнес-логіки.
  • Процес аспектної орієнтації та розробки програмного забезпечення може включати моделювання, дизайн, програмування, зворотний інженіринг, реінженіринг.
  • Зона покриття аспектно-орієнтованої розробки ПЗ включаєдодатки, компоненти, бази даних.
  • Взаємодія та інтеграція з іншими парадигмами здійснюється за допомогою фреймворків, генераторів, мов програмування та мов опису архітектури (ADL).

Основи аспектно-орієнтованого підходу

Щоб краще зрозуміти базиси АОП, повернімося до прикладу з виділенням аспекту моніторингу продуктивності (див. рис. 2). Нам потрібно зняти показання таймера на вході та на виході всіх методів класів Model, Document, Record, Dispatcher. Отже, ми маємо аспект Logging. Нам потрібно буде завести до нього Pointcut з перерахуванням усіх потрібних функцій. У більшості мов програмування, що підтримують АОП, для охоплення всіх методів класу можна використовувати спеціальну маску. Тепер можна описати для цього Pointcut. Створюємо Advice на вході у методи зі списку Pointcut (Before) та на виході з них (After). Advice для подій Before, After, Around – найбільш популярні у мовах, що підтримують АОП, але часом доступні й інші події.

Отже, за результатами цього прикладу можна відзначити собі з приводу базисних декларацій АОП наступне:

Aspect- визначення деякого набору наскрізної функціональності, орієнтованої на конкретне завдання;

Poincut- код застосування аспекту. Відповідає питання, де і коли може бути застосована функціональність даного аспекту (див. малюнок 3)

Advice- код функціональності об'єкта. Безпосередньо код функціональності для заданих подій. Іншими словами, це те, що буде виконано для об'єктів, зазначених у Pointcut.

Все ще важко вникнути у цей підхід? Гадаю, все стане на свої місця, коли ми привнесемо трохи предметності. Почнемо з найпростішого прикладу. Я колись написав цю маленькубібліотеку спеціально, щоб проілюструвати як переваги підходу АОП, і його доступність. Крім того, для того, щоб скористатися цією бібліотекою вам не знадобляться глибокі знання PHP та спеціального програмного забезпечення. Вам буде достатньо включити бібліотеку aop.lib.php у ваші скрипти під керуванням PHP 4 (або вище) у його стандартній комплектації. Ми можемо визначити певний аспект для наскрізної функціональності (скажімо, ведення журналів транзакцій) за допомогою ініціювання класу Aspect.

Далі ми можемо створити Pointcut і повідомити, які методи він торкається.

Залишилося лише повідомити програмний код для вхідних та вихідних точок методів поточного зрізу.

Аналогічно ми можемо описати додатковий аспект, наприклад:

Щоб задіяти один або кілька аспектів, достатньо скористатися функцією Aspect::apply()

Як вам, можливо, відомо, у PHP до 5-ї версії досить проблематично обслуговувати події методів та класів. Якщо для подій глобального характеру, таких як помилки PHP, можна написати власний обробник, то для обробки, скажімо, подій на вході та виході методів доведеться "вручну" розставити "оповіщувачі". У нашому випадку потрібно розставляти спеціальні функції

Як бачимо з прикладу, до коду бізнес-логіки методу і після нього встановлено "оповіщувачі" цих подій. Коли процесор PHP мине такий "оповіщувач", він перевіряє, чи немає активних аспектів. У разі наявності такого, PHP перевіряє, чи вказано поточну функцію в діапазоні Pointcut. Якщо ця умова вірна, викликається призначена нами функція для цієї події (наприклад для Advice::_before()). Бачите – як я і обіцяв, все досить просто. Але чи дає цей підхід реальну користь?

Давайтеуявімо, що ми розставили у всіх методах класів наших скриптів "оповісники" та підключили бібліотеку aop.lib.php. І ось одного разу нам потрібно було отримати детальний звіт про розподіл навантаження за функціями нашого проекту, що виконуються. Ми створюємо аспект та призначаємо йому Pointcut, що охоплює всі функції проекту.

Як показано у прикладі, ми можемо скористатися маскою *:: *. Далі в Advice ми можемо скористатися традиційною функцією обчислення точного часу в мілісекундах

За допомогою цієї функції ми можемо заміряти час на вході в кожну функцію проекту та звіряти його зі свідченнями на виході з цієї функції, а час виконання операцій бізнес-логіки в тілі функції поміщати у глобальну змінну звіту. Залишилося лише вивести на екран звіт наприкінці програми. Приклад використання аспекту моніторингу продуктивності представлено у скрипті sample_trace.php в архіві дистрибутивного пакета.

Щоб у вас не склалася думка, що АОП допомагає вирішувати лише якісь приватні завдання, розглянемо ще приклад.

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

Що особливо цікаво, за допомогою АОП ми можемо призначити специфічне виведення повідомлення про системну помилку для певного набору функцій. Допустимо, низка наших функцій бере участь у формуванні коду розмітки WML (WAP), WSDL (SOAP), RSS/ATOM або SVG. Зрозуміло, у разі неприпустимо виводити на екран HTML-разметку з повідомленням про помилку. "Сповісник" в обробнику помилок PHP змусить систему відобразити повідомлення або в потрібній розмітці XML, або сповістити нас без відображення повідомлення на екрані(Наприклад, по Email).

Кожен, кому доводилося брати участь у розробці програмних продуктів, що тиражуються, знає, наскільки непросто вирішити проблему оновлення версій продукту. Звичайно, всі ми знаємо про наявність спеціального програмного забезпечення для контролю версій, наприклад, CVS (Concurrent Versions System). Однак проблема полягає в тому, що для кожного нового продукту на базі нашого продукту, що тиражується, потрібна деяка кастомізації, і часто досить складно з'ясувати, чи не торкнеться оновлення області, адаптовані під конкретний проект. Напевно, хтось із вас зустрічався з проблемою, коли після чергового оновлення версії базового продукту доводилося відновлювати весь проект із резервних копій. А уявіть собі ситуацію, коли "зникнення" кастомізації в окремих інтерфейсах проекту з'ясовується через тривалий час після оновлення версії базового продукту! Ви скажете "А до чого тут АОП?!". Справа в тому, що АОП якраз може допомогти у вирішенні цієї проблеми. Адже ми можемо перенести весь код кастомізації проекту як наскрізну функціональність за межі основної бізнес-логіки. Достатньо визначити аспект наших інтересів, вказати область його застосування (Pointcut) та розробити відповідний код функціональності. Має сенс глянути на те, як це може працювати.

Аспектно-орієнтована Розробка ПЗ на PHP

Ці скрипти, за необхідності, можуть бути задіяні шляхом вказівки при декларації коду AOPHP

У проекті Seasar.PHP використано інший шлях. Тут для структурування декларацій аспектів використовується XML, а компонування робить сам PHP, після чого виконує результуючий код за допомогою функції eval().

У проекті MFAOP використовується принцип, трохи схожий на той, що я демонстрував вищеприклади. Автор проекту рекомендує спочатку призначити деякий Poincut і надалі його застосовувати в різних аспектах.

На відміну від бібліотеки aop.lib.php у цьому рішенні у вас немає необхідності розставляти "оповіщувачі" "вручну" для кожної функції. Але доведеться інсталювати на сервері додаткове розширення PHP PECL Classkit.

Як бачимо, у прикладі область заданого аспекту чітко визначена. Завдання Pointcut і Advice настільки лаконічне, але ємне, що складається враження, що це "рідний" синтаксис PHP. Даний проект пропонує обслуговування подій Join point семи (!) типів: виклик методу (call), виконання методу (exec), ініціалізація класу (new), запис до атрибуту (set), читання атрибуту (get), деструкція класу (unset) та захоплення блоку (catch). Можливе завдання Advice трьох типів: before, after, around. Проект дозволяє використовувати несподівано гнучкі маски для завдання областей спостереження Pointcut. Приміром, є можливість завдання області всім класів із заданим префіксом у імені.

Для встановлення PHPAspect вам знадобиться PHP версії не нижче 5.0.0 та встановлені бібліотеки PEAR Console_Getopt, Console_ProgressBar, PHP_Beautifier.

Висновок

АОП також вимагає тривалого періоду звикання, як, наприклад, TDD. Спочатку можна виносити в аспекти просту наскрізну функціональність, таку як протоколювання. А згодом можна дедалі більше розширювати декомпозицію програмної архітектури, збираючи у галузях аспектів різні сфери застосування програми.