Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Programowanie aspektowe w PHP

Mariusz Gil
September 30, 2012

Programowanie aspektowe w PHP

Abstrakt prezentacji:

Programowanie obiektowe możemy postrzegać jako dwuwymiarową przestrzeń klas, obiektów i występujących pomiędzy nimi interakcji w postaci np. wywołań metod. Na przestrzeni lat powstało także wiele metod i rozwiązań pomagających zapanować nad tworzącą się w ten sposób skomplikowaną siecią, warto by tu wspomnieć choćby enkapsulację, wzorce GoF czy GRASP. Niemal zawsze pojawiają się jednak zagadnienia przecinające przestrzeń ortogonalnie, bez związku z konkretną funkcjonalnością. Przeplot logiki aplikacyjnej z dodatkowym kodem realizującym zadania poboczne (tzw. warkocz) utrudnia jego analizowanie czy debugowanie. Trudno chyba sobie jednak wyobrazić aplikację bez systemu logowania zdarzeń, czy pomiaru czasów wykonania poszczególnych fragmentów kodu w trybie debug.

Z pomocą w implementacji logiki ortogonalnej przychodzi paradygmat programowania aspektowego, opracowany przez Gregora Kiczalesa w laboratoriach Xerox PARC. Za jego pomocą można niejako stworzyć trzeci wymiar, w którym umieszczana i implementowana jest logika ortogonalna, którą na dodatek można natychmiastowo włączać/wyłączać w całym kodzie źródłowym, bez potrzeby jego modyfikacji! Największe sukcesy paradygmatu AOP są związane z językiem Java (i kompilatorem AspecjJ), to jednak istnieje szereg rozwiązań dla PHP, dzięki którym nasz kod może stać się jeszcze bardziej modularny czy też “re-używalny”.

W trakcie sesji zapoznamy się z terminologią wykorzystywaną w AOP, zasadę tworzenia i wykorzystywania aspektów oraz możliwe do zastosowania biblioteki i frameworki PHP.

Mariusz Gil

September 30, 2012
Tweet

More Decks by Mariusz Gil

Other Decks in Programming

Transcript

  1. class UserService { //... public function delete($user) { $this->logger->push(„Operation started

    at: ” . time()); if ($this->user->isAuthenticated()) { if ($this->user->isAllowedTo(self::DELETE) { $payments = PaymentPeer::retrieveByUser($user); foreach ($payments as $payment) { $payment->deleteFromCache(); $payment->delete(); } $user->deleteFromCache(); $user->delete(); } else { throw new UnauthorizedAccessException(); } } else { throw new UnauthorizedAccessException(); } $this->logger->push(„Operation finished at: ” . time()); } }
  2. 1

  3. 2

  4. 3

  5. wiele problemó WZORCE PROJEKTOWE WZORCE GRASP DESIGN BY CONTRACTS ZASADY

    SOLID ZASADA DRY ZASADA KISS ZASADA YAGNI ` wiele rozwiazan `
  6. Programowanie aspektowe (aspect-oriented programming, AOP) paradygmat tworzenia programów komputerowych wspomagajacy

    separacje zagadnien i rozdzielenie programu na czesci w jak najwiekszym stopniu niezwiazane funkcjonalnie ` , , , , , `
  7. class UserService { //... public function delete($user) { $this->logger->push(„Operation started

    at: ” . time()); if ($this->user->isAuthenticated()) { if ($this->user->isAllowedTo(self::DELETE) { $payments = PaymentPeer::retrieveByUser($user); foreach ($payments as $payment) { $payment->deleteFromCache(); $payment->delete(); } $user->deleteFromCache(); $user->delete(); } else { throw new UnauthorizedAccessException(); } } else { throw new UnauthorizedAccessException(); } $this->logger->push(„Operation finished at: ” . time()); } }
  8. PUNKT ZLACZENIA dowolny identyfikowalny punkt programu, moze nim byc wywolanie

    lub wykonanie metody/konstruktora, odwolanie do pola w klasie obsluga wyjatku, etc. 1 ` . - - - - `
  9. KORZYSCI? ` + modularyzacja kodu + wieksza czytelnosc + separacja

    zagadnien + aktywacja i zmiana flo całej aplikacji ` ` ` `
  10. /** * Simple book bean class. * * @package demo

    * @version 1.0 */ class Book { /** * */ public $author; public $title; public $description; }
  11. /** * Simple storage bean class. * * @package demo

    * @version 1.0 */ class Storage { /** * */ public function store($model, $field, $value) { echo sprintf( "*** Store method executed: model \"%s\", field \"%s\", value \"%s\"\n", $model, $field, $value ); } /** * */ public function load($model, $field) { echo sprintf( "*** Load method executed: model \"%s\", field \"%s\"\n", $model, $field ); } }
  12. /** * Simple aspects. * * @package demo * @version

    1.0 */ $storage = new Storage(); $storageAdvice = function (AopTriggeredJoinPoint $joinpoint) use ($storage) { switch ($joinpoint->getKindOfAdvice()) { case AOP_KIND_BEFORE_READ_PROPERTY: $storage->load( $joinpoint->getTriggeringClassName(), $joinpoint->getTriggeringPropertyName() ); break; case AOP_KIND_AFTER_READ_PROPERTY: break; case AOP_KIND_BEFORE_WRITE_PROPERTY: break; case AOP_KIND_AFTER_WRITE_PROPERTY: $storage->store( $joinpoint->getTriggeringClassName(), $joinpoint->getTriggeringPropertyName(), $joinpoint->getAssignedValue() ); break; } };
  13. /** * Simple aspects. * * @package demo * @version

    1.0 */ $storage = new Storage(); $storageAdvice = function (AopTriggeredJoinPoint $joinpoint) use ($storage) { switch ($joinpoint->getKindOfAdvice()) { case AOP_KIND_BEFORE: case AOP_KIND_BEFORE_METHOD: case AOP_KIND_BEFORE_FUNCTION: case AOP_KIND_BEFORE_PROPERTY: case AOP_KIND_BEFORE_READ_PROPERTY: case AOP_KIND_BEFORE_WRITE_PROPERTY: case AOP_KIND_AROUND: case AOP_KIND_AROUND_METHOD: case AOP_KIND_AROUND_FUNCTION: case AOP_KIND_AROUND_PROPERTY: case AOP_KIND_AROUND_READ_PROPERTY: case AOP_KIND_AROUND_WRITE_PROPERTY: case AOP_KIND_AFTER: case AOP_KIND_AFTER_METHOD: case AOP_KIND_AFTER_FUNCTION: case AOP_KIND_AFTER_PROPERTY: case AOP_KIND_AFTER_READ_PROPERTY: case AOP_KIND_AFTER_WRITE_PROPERTY: break; } };
  14. /** * Simple aspect demo script. * * @param package

    demo * @version 1.0 */ require 'classes.php'; require 'aspects.php'; aop_add_before('Book->*', $storageAdvice); aop_add_after('Book->*', $storageAdvice); $book = new Book(); $book->title = 'Lorem ipsum'; $book->description = 'Lorem ipsum'; var_dump($book->title);
  15. /** * Simple aspect demo script. * * @param package

    demo * @version 1.0 */ require 'classes.php'; require 'aspects.php'; aop_add_after('MyClass->myMethod()', $sampleAdvice); aop_add_after('MyClass->my*()', $sampleAdvice); aop_add_after('MyClass->*()', $sampleAdvice); aop_add_after('*::myMethod()', $sampleAdvice); aop_add_after('**\*()', $sampleAdvice); aop_add_after('\namespace\MyClass->property', $sampleAdvice); aop_add_after('public MyClass->property', $sampleAdvice); aop_add_after('!public MyClass->*', $sampleAdvice); aop_add_after('public|private MyClass->*', $sampleAdvice); aop_add_after('read MyClass->*', $sampleAdvice);
  16. namespace  Examples\Forum\Domain\Model; class  Forum  {    /**      *

     @FLOW3\Inject      *  @var  \Examples\Forum\Logger\ApplicationLoggerInterface      */    protected  $applicationLogger;    /**      *  Delete  a  forum  post  and  log  operation      *      *  @param  \Examples\Forum\Domain\Model\Post  $post      *  @return  void      */      public  function  deletePost(Post  $post)  {          $this-­‐>applicationLogger-­‐>log('Removing  post  '  .  $post-­‐>getTitle(),  LOG_INFO);          $this-­‐>posts-­‐>remove($post);      } }
  17. namespace Examples\Forum\Logging; /** * @FLOW3\Aspect */ class LoggingAspect { /**

    * @FLOW3\Inject * @var \Examples\Forum\Logger\ApplicationLoggerInterface */ protected $applicationLogger; /** * Log a message if a post is deleted * * @param \TYPO3\FLOW3\AOP\JoinPointInterface $joinPoint * @FLOW3\Before("method(Examples\Forum\Domain\Model\Forum->deletePost())") * @return void */ public function logDeletePost(\TYPO3\FLOW3\AOP\JoinPointInterface $joinPoint) { $post = $joinPoint->getMethodArgument('post'); $this->applicationLogger->log('Removing post ' . $post->getTitle(), LOG_INFO); } }