2013-05-19 17 views
7

Ho un'idea per il sistema di eventi che sto sviluppando per il mio framework personalizzato.Possiamo aggiungere più linee in una funzione estendendola con PHP?

Immaginate una pseudo-funzione come questa.

class Test 
{ 
    public function hi() 
    { 
     Event::add(__FUNCTION__ . 'is about to run.'); 
     return "hi"; 
    } 
} 

Immagina di aver bisogno di fare lo stesso per altre funzioni. (Forse si desidera registrare le funzioni eseguite nel runtime e si desidera registrarle in un file separato.)

Invece di eseguire questa operazione e aggiungere Eventi alle funzioni manualmente, è possibile fare qualcosa di simile?

class Test 
{ 
    public function hi() 
    { 
     return "hi"; 
    } 
} 

// events.php (It's a pseudo code so may not work.) 
// Imagine extend's purpose is to inject codes into target function 

Event::bind('on', $className, $methodName, function() use ($className, $methodName) 
{ 
    return $className->$methodName->extend('before', Event::add(__FUNCTION__ . 'is about to run.')); 
}); 

L'idea è di iniettare hi() funzione che è all'interno Test class e iniettare ciò passiamo extend funzione all'esterno. 'before' significa che l'iniezione deve essere nella prima riga della funzione target.

Infine, gli eventi e gli eventi collegati vengono tenuti completamente distanti dalle funzioni. Voglio essere in grado di associare le cose personalizzate senza alterare le funzioni.

Ho la sensazione che possiamo fare questo hacking con eval() o giocando con call_user_func(). Non sono sicuro, però. L'utilizzo di eval() sembra già abbastanza brutto.

La mia domanda è;

  1. È possibile fare qualcosa con PHP?
  2. Ha un nome nei principi OOP/OOP, quindi posso leggere oltre?
  3. Ha senso o è una cattiva idea?
+0

Ho pensato che il punto principale dell'utilizzo delle classi era di riutilizzarli? –

+0

Non sicuro. Forse un proxy? –

+2

[Iniezione di dipendenza] (http://en.wikipedia.org/wiki/Dependency_injection)? Fowler è sempre una buona risorsa quando si tratta di modelli di design. http://www.martinfowler.com/articles/injection.html. ** Evita 'eval' **. – ficuscr

risposta

2

Sì, è possibile. È possibile utilizzare AOP utilizzando GO! AOP framework che funziona sulle annotazioni.

Ad esempio, si desidera registrare ogni chiamata al metodo pubblico. Invece di aggiungere a ogni riga di funzione come questa.

namespace Acme; 

class Controller 
{ 
    public function updateData($arg1, $arg2) 
    { 
     $this->logger->info("Executing method " . __METHOD__, func_get_args()); 
     // ... 
    }  
} 

È possibile utilizzare uno Aspect per tutti i metodi pubblici di tutte le classi di Acme namespace come questo:

use Go\Aop\Aspect; 
use Go\Aop\Intercept\MethodInvocation; 
use Go\Lang\Annotation\Before; 

    class LoggingAspect implements Aspect 
    { 
     /** @var null|LoggerInterface */ 
     protected $logger = null; 

     /** ... */ 
     public function __construct($logger) 
     { 
      $this->logger = $logger; 
     } 

     /** 
     * Method that should be called before real method 
     * 
     * @param MethodInvocation $invocation Invocation 
     * @Before("execution(public Acme\*->*())") 
     */ 
     public function beforeMethodExecution(MethodInvocation $invocation) 
     { 
      $obj = $invocation->getThis(); 
      $class = is_object($obj) ? get_class($obj) : $obj; 
      $type = $invocation->getMethod()->isStatic() ? '::' : '->'; 
      $name = $invocation->getMethod()->getName(); 
      $method = $class . $type . $name; 

      $this->logger->info("Executing method " . $method, $invocation->getArguments()); 
     } 
    }  

sembra più complicato, ma è più flessibile.