2013-05-19 24 views
7

Tôi có ý tưởng về hệ thống sự kiện mà tôi đang phát triển cho khung tùy chỉnh của mình.Chúng ta có thể tiêm thêm một số dòng trong một hàm bằng cách mở rộng nó bằng PHP không?

Hãy tưởng tượng một chức năng giả như thế này.

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

Hãy tưởng tượng bạn cần làm tương tự cho một số chức năng khác. (Có thể bạn muốn ghi lại các chức năng nào chạy trong thời gian chạy và muốn ghi chúng vào một tệp riêng.)

Thay vì thực hiện việc này và thêm Sự kiện vào thủ công, chúng ta có thể làm điều gì đó như thế này không?

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.')); 
}); 

Ý tưởng là để tiêm hi() chức năng mà là bên trong Test class và tiêm bất cứ điều gì chúng tôi vượt qua trong extend chức năng bởi bên ngoài. 'before' có nghĩa là tiêm phải nằm ở hàng đầu tiên của hàm mục tiêu.

Cuối cùng, các sự kiện và sự kiện ràng buộc được giữ hoàn toàn trừu tượng ra khỏi các chức năng. Tôi muốn có thể ràng buộc những thứ tùy chỉnh mà không thay đổi các chức năng.

Tôi có cảm giác rằng chúng tôi có thể làm điều này bằng cách hack xung quanh với eval() hoặc bằng cách đồ chơi với call_user_func(). Tôi không chắc chắn, mặc dù. Sử dụng eval() âm thanh khá tệ rồi.

Câu hỏi của tôi là;

  1. Có thể làm gì với PHP không?
  2. Có tên trong Nguyên tắc OOP/OOP để tôi có thể đọc thêm không?
  3. Ứng dụng có ý nghĩa hay ý tưởng tồi không?
+0

Tôi nghĩ rằng toàn bộ điểm sử dụng các lớp học là sử dụng lại chúng? –

+0

Không chắc chắn. Proxy có thể? –

+2

[Dependency Injection] (http://en.wikipedia.org/wiki/Dependency_injection)? Fowler luôn là một nguồn lực tốt khi nói đến các mẫu thiết kế. http://www.martinfowler.com/articles/injection.html. ** Tránh 'eval' **. – ficuscr

Trả lời

2

Có, bạn có thể. Bạn có thể sử dụng AOP bằng cách sử dụng GO! AOP framework hoạt động trên chú thích.

Ví dụ: bạn muốn ghi lại mọi phương thức gọi công khai. Thay vì thêm vào mỗi dòng chức năng như thế này.

namespace Acme; 

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

Bạn có thể sử dụng một Aspect cho tất cả các phương pháp công cộng của mọi tầng lớp nhân Acme namespace như thế này:

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()); 
     } 
    }  

Có vẻ phức tạp hơn nhưng nó linh hoạt hơn.