Vì vậy, giả sử bạn không muốn mẫu Observer bởi vì nó yêu cầu bạn thay đổi các phương thức lớp để xử lý công việc lắng nghe và muốn một cái gì đó chung chung. Và giả sử bạn không muốn sử dụng extends
quyền thừa kế vì bạn có thể đã được thừa kế trong lớp của mình từ một số lớp khác. Sẽ không tuyệt vời khi có một cách chung để làm cho bất kỳ lớp nào có thể cắm được mà không cần nhiều nỗ lực ? Đây là cách thực hiện:
<?php
////////////////////
// PART 1
////////////////////
class Plugin {
private $_RefObject;
private $_Class = '';
public function __construct(&$RefObject) {
$this->_Class = get_class(&$RefObject);
$this->_RefObject = $RefObject;
}
public function __set($sProperty,$mixed) {
$sPlugin = $this->_Class . '_' . $sProperty . '_setEvent';
if (is_callable($sPlugin)) {
$mixed = call_user_func_array($sPlugin, $mixed);
}
$this->_RefObject->$sProperty = $mixed;
}
public function __get($sProperty) {
$asItems = (array) $this->_RefObject;
$mixed = $asItems[$sProperty];
$sPlugin = $this->_Class . '_' . $sProperty . '_getEvent';
if (is_callable($sPlugin)) {
$mixed = call_user_func_array($sPlugin, $mixed);
}
return $mixed;
}
public function __call($sMethod,$mixed) {
$sPlugin = $this->_Class . '_' . $sMethod . '_beforeEvent';
if (is_callable($sPlugin)) {
$mixed = call_user_func_array($sPlugin, $mixed);
}
if ($mixed != 'BLOCK_EVENT') {
call_user_func_array(array(&$this->_RefObject, $sMethod), $mixed);
$sPlugin = $this->_Class . '_' . $sMethod . '_afterEvent';
if (is_callable($sPlugin)) {
call_user_func_array($sPlugin, $mixed);
}
}
}
} //end class Plugin
class Pluggable extends Plugin {
} //end class Pluggable
////////////////////
// PART 2
////////////////////
class Dog {
public $Name = '';
public function bark(&$sHow) {
echo "$sHow<br />\n";
}
public function sayName() {
echo "<br />\nMy Name is: " . $this->Name . "<br />\n";
}
} //end class Dog
$Dog = new Dog();
////////////////////
// PART 3
////////////////////
$PDog = new Pluggable($Dog);
function Dog_bark_beforeEvent(&$mixed) {
$mixed = 'Woof'; // Override saying 'meow' with 'Woof'
//$mixed = 'BLOCK_EVENT'; // if you want to block the event
return $mixed;
}
function Dog_bark_afterEvent(&$mixed) {
echo $mixed; // show the override
}
function Dog_Name_setEvent(&$mixed) {
$mixed = 'Coco'; // override 'Fido' with 'Coco'
return $mixed;
}
function Dog_Name_getEvent(&$mixed) {
$mixed = 'Different'; // override 'Coco' with 'Different'
return $mixed;
}
////////////////////
// PART 4
////////////////////
$PDog->Name = 'Fido';
$PDog->Bark('meow');
$PDog->SayName();
echo 'My New Name is: ' . $PDog->Name;
Trong Phần 1, đó là những gì bạn có thể bao gồm với một require_once()
cuộc gọi ở đầu tập lệnh PHP của bạn. Nó tải các lớp để làm cho một cái gì đó có thể cắm được.
Trong Phần 2, đó là nơi chúng ta tải một lớp. Lưu ý tôi đã không phải làm bất cứ điều gì đặc biệt cho lớp, khác biệt đáng kể so với mẫu Người quan sát.
Trong Phần 3, đó là nơi chúng ta chuyển lớp của mình thành "có thể cắm được" (nghĩa là, hỗ trợ các plugin cho phép chúng ta ghi đè các phương thức và thuộc tính của lớp). Vì vậy, ví dụ, nếu bạn có một ứng dụng web, bạn có thể có một sổ đăng ký plugin và bạn có thể kích hoạt các plugin ở đây. Cũng lưu ý Dog_bark_beforeEvent()
chức năng. Nếu tôi đặt $mixed = 'BLOCK_EVENT'
trước câu lệnh return, nó sẽ chặn con chó sủa và cũng sẽ chặn Dog_bark_afterEvent vì sẽ không có sự kiện nào.
Trong Phần 4, đó là mã hoạt động bình thường, nhưng lưu ý rằng những gì bạn có thể nghĩ sẽ chạy hoàn toàn không chạy như vậy. Chẳng hạn, con chó không thông báo tên của nó là 'Fido', mà là 'Coco'. Con chó không nói 'meo', mà là 'Woo'. Và khi bạn muốn nhìn vào tên của con chó sau đó, bạn sẽ thấy nó là 'Khác biệt' thay vì 'Coco'. Tất cả các phần ghi đè được cung cấp trong Phần 3.
Vậy làm thế nào để làm việc này? Chà, hãy loại trừ eval()
(mà mọi người nói là "xấu xa") và loại trừ rằng đó không phải là mẫu Người quan sát. Vì vậy, cách nó hoạt động là lớp trống lén lút được gọi là Pluggable, không chứa các phương thức và thuộc tính được sử dụng bởi lớp Dog. Do đó, kể từ khi điều đó xảy ra, các phương pháp ma thuật sẽ tham gia vào chúng ta. Đó là lý do tại sao trong phần 3 và 4, chúng ta gặp rắc rối với đối tượng xuất phát từ lớp Pluggable chứ không phải lớp Dog. Thay vào đó, chúng tôi để lớp Plugin thực hiện "chạm" vào đối tượng Dog cho chúng tôi. (Nếu đó là một kiểu mẫu thiết kế mà tôi không biết - vui lòng cho tôi biết.)