2012-03-01 30 views
9

Làm việc với một lớp thư viện PHP, và tôi muốn để bọc tất cả các chức năng công cộng của nó trong một lớp con ... Một cái gì đó dọc theo dòng:PHP: Quấn tất cả các chức năng của một lớp trong một lớp con

class BaseClass 
{ 
    function do_something() 
    { 
     some; 
     stuff; 
    } 

    function do_something_else() 
    { 
     other; 
     stuff; 
    } 

    /* 
    * 20-or-so other functions here! 
    */ 
} 

class SubClass extends BaseClass 
{ 
    function magicalOverrideEveryone() 
    { 
     stuff-to-do-before;  // i.e. Display header 
     call_original_function(); // i.e. Display otherwise-undecorated content 
     stuff-to-do-after;   // i.e. Display footer 
    } 
} 

Đun sôi nó xuống, tôi không muốn phải ghi đè lên mọi phương thức siêu lớp với cùng mã bao bọc, nếu có một cách [hơi thanh lịch/sạch] để làm tất cả ở một nơi.

Điều này có khả thi không? Tôi nghi ngờ tôi đang ở trong đất Lập trình meta ở đây, và thậm chí không biết nếu PHP cung cấp một con thú như vậy, nhưng figured tôi muốn hỏi ...

+0

Để làm rõ - Chỉ có một số phương pháp từ 'BaseClass' mà bạn muốn ghi đè trong' SubClass', không phải tất cả chúng? –

+0

@ s992, không chính xác - Tôi đang tìm cách áp dụng cùng một mã trình bao bọc cho mọi phương thức trong lớp cơ sở. Có vẻ như phương thức ma thuật __call của PHP sẽ thực hiện công việc với một trình bao bọc proxy, nhờ @meagar! – mtbkrdave

+0

Gotcha, câu hỏi không rõ ràng. Nếu câu trả lời của meagar giúp bạn, bạn nên chấp nhận nó. :) –

Trả lời

16

Bạn có thể thực hiện điều này một cách dễ dàng với __callmagic method và lớp "proxy" chung không kế thừa trực tiếp từ lớp cơ sở.

Dưới đây là một (gần) hoàn thành việc thực hiện một lớp proxy mà kết thúc tốt đẹp bất cứ đối tượng nào bạn vượt qua nó. Nó sẽ gọi một số mã "trước" và "sau" xung quanh mỗi cuộc gọi phương thức.

class MyProxy { 
    function __construct($object) { 
    $this->object = $object; 
    } 

    function __call($method, $args) { 
    // Run before code here 

    // Invoke original method on our proxied object 
    call_user_func_array(array($this->object, $method), $args); 

    // Run after code here 
    } 
} 


$base = new BaseClass(); 
$proxy = new MyProxy($base); 

$proxy->doSomething(); // invoke $base->doSomething(); 

Bạn sẽ đương nhiên muốn thêm một chút xử lý lỗi, như yêu cầu các đối tượng proxy nếu nó phản ứng với các phương pháp được đưa ra trong __call và nâng cao một lỗi nếu nó không. Bạn thậm chí có thể thiết kế lớp Proxy là lớp cơ sở cho các proxy khác. Các lớp proxy con có thể triển khai các phương thức beforeafter.

Nhược điểm là "lớp con" không còn thực hiện BaseClass, có nghĩa là nếu bạn đang sử dụng type-hinting và muốn yêu cầu chỉ đối tượng thuộc loại BaseClass được chuyển vào một hàm, cách tiếp cận này sẽ không thành công.

+0

Hiện tượng - đây chính xác là những gì tôi đang tìm kiếm! – mtbkrdave

+0

Ngoài ra ... WOW đã nhanh chóng! Đừng bao giờ đánh giá thấp sức mạnh của Stackoverflow! – mtbkrdave

+1

Một cách để phá vỡ vấn đề kiểu là xem phiên bản PHP của Mockito, Phockito, tạo ra các lớp Mock như thế nào. https://github.com/hafriedlander/phockito/blob/master/Phockito.php#L170 –

0

bạn có thể tìm kiếm các mô hình trang trí:

class A 
{ 
    function do1(){ 

    } 
} 
class DecoratorForA extends A 
{ 
    private A original; 
    public DecoratorForA(A original) 
    { 
     this.original = original; 
    } 
    function do1(){ //<-- override keyword in php? 
     stuffBefore(); 
     original->do1(); 
     stuffAfter();  
    } 
} 

vì đây không phải là điều bạn muốn, có thể liên kết này là trợ giúp? http://code.google.com/p/php-aop/

+0

oh, bây giờ tôi đọc nó một cách chính xác, đoán bạn không tìm kiếm điều đó. – mindandmedia

+0

Anh ấy đang cố gắng tìm một cách đơn giản để áp dụng chung kiểu trang trí * mà không cần * viết một độ lớn mã soạn sẵn. Bạn chỉ cần cung cấp cho một nhu cầu của mình một tên, không phải là một giải pháp ... – rodneyrehm

+0

Đúng, tôi đã tìm kiếm một ứng dụng metaprogramming của mô hình trang trí ... Cảm ơn bạn đã đầu vào của bạn, mặc dù! – mtbkrdave

2

Nếu tên phương thức của SubClass có thể hơi khác so với tên phương pháp gốc của BaseClass, bạn có thể viết trình bao bọc chung với __call(). Nếu tên phương thức phải khớp, tôi không thấy cách bạn có thể đạt được mục tiêu của mình mà không ghi đè lên từng phương pháp theo cách thủ công. Có lẽ bạn có thể sử dụng funcall PECL để làm điều này - nhưng bạn phải có khả năng tải PECL đó ngay từ đầu.

Nếu bạn có thể thực hiện các phương pháp của BaseClass protected, cách tiếp cận __call() trong SubClass sẽ hoạt động.

Nếu bạn không cần để gia hạn lớp học, cách tiếp cận @ ít ỏi là hoàn toàn ổn. Xin lưu ý rằng __call() và call_user_func_array() làm áp đặt một chi phí nào đó.

+0

Đây là điều quan trọng cần chỉ ra - cảm ơn. Tôi không (nghĩ rằng tôi) cần phải mở rộng các lớp học, vì vậy tôi dự đoán cách tiếp cận proxy sẽ làm việc. (Sẽ phụ thuộc vào cách định tuyến CodeIgniter được thực hiện dưới mui xe) – mtbkrdave

0

Nếu tôi hiểu bạn đúng, bạn muốn mở rộng một lớp học, nhưng không cho phép bất kỳ phương thức nào từ phụ huynh được gọi. Thay vào đó, bạn muốn tự gọi tất cả các phương thức trong một phương thức trong lớp mới.

Vậy tại sao bạn thậm chí muốn kế thừa ngay từ đầu? Nghe có vẻ như bạn chỉ cần tạo một bộ chuyển đổi/trang trí cho BaseClass của bạn.

class SubClass 
{ 
    function magicalOverrideEveryone() 
    { 
     BaseClass bc = new BaseClass(); 
     bc.do_something(); 
     bc.do_something_else(); 
    } 
} 
Các vấn đề liên quan