Để mở rộng câu trả lời của Berry, rằng việc thiết lập mức truy cập thành protected cho phép __get và __set được sử dụng với các thuộc tính được khai báo rõ ràng (ít nhất là khi được truy cập bên ngoài lớp) và tốc độ chậm hơn đáng kể, tôi sẽ trích dẫn nhận xét từ một câu hỏi khác về chủ đề này và vẫn đưa ra trường hợp sử dụng nó:
Tôi đồng ý rằng __get chậm hơn đối với hàm get tùy chỉnh (thực hiện những điều tương tự), đây là 0,0124455 thời gian cho __get () và 0,0024445 này là cho get () tùy chỉnh sau 10000 vòng. - Melsi 23 tháng 11 '12 lúc 22:32 Phương pháp hay nhất: Phương pháp ma thuật PHP __set và __get
Theo các thử nghiệm của Melsi, chậm hơn đáng kể là chậm hơn khoảng 5 lần. Điều đó chắc chắn chậm hơn đáng kể, nhưng cũng lưu ý rằng các thử nghiệm cho thấy rằng bạn vẫn có thể truy cập thuộc tính bằng phương pháp này 10.000 lần, tính thời gian lặp lại vòng lặp, trong khoảng 1/100 giây. Nó chậm hơn đáng kể so với các phương thức get và set thực tế được định nghĩa và đó là một cách nói ngắn gọn, nhưng trong sơ đồ tổng thể của mọi thứ, thậm chí chậm hơn 5 lần cũng không bao giờ thực sự chậm.
Thời gian tính toán của hoạt động vẫn không đáng kể và không đáng để xem xét trong 99% các ứng dụng thế giới thực. Lần duy nhất nó thực sự nên tránh là khi bạn thực sự sẽ truy cập các thuộc tính hơn 10.000 lần trong một yêu cầu duy nhất. Các trang web có lưu lượng truy cập cao đang làm điều gì đó thực sự sai nếu họ không đủ khả năng cung cấp thêm một vài máy chủ để giữ cho ứng dụng của họ hoạt động. Một quảng cáo văn bản một dòng trên chân trang của một trang web có lưu lượng truy cập cao, nơi tỷ lệ truy cập trở thành một vấn đề có thể phải trả cho một nhóm 1.000 máy chủ có dòng văn bản đó. Người dùng cuối sẽ không bao giờ gõ ngón tay của họ để tự hỏi điều gì đang khiến trang tải quá lâu vì quyền truy cập thuộc tính của ứng dụng của bạn mất một phần triệu giây.
Tôi nói điều này với tư cách là một nhà phát triển đến từ nền tảng .NET, nhưng các phương thức nhận và thiết lập vô hình cho người tiêu dùng không phải là phát minh của .NET. Đơn giản là chúng không phải là thuộc tính nếu không có chúng, và những phương thức kỳ diệu này là ân huệ của nhà phát triển PHP khi thậm chí còn gọi phiên bản thuộc tính của chúng là "thuộc tính". Ngoài ra, phần mở rộng Visual Studio dành cho PHP không hỗ trợ intellisense với các thuộc tính được bảo vệ, tôi nghĩ vậy với mẹo đó. Tôi nghĩ rằng với đủ các nhà phát triển sử dụng các phương thức __get và __set kỳ diệu theo cách này, các nhà phát triển PHP sẽ điều chỉnh thời gian thực thi để phục vụ cho cộng đồng nhà phát triển.
Chỉnh sửa: Về lý thuyết, các thuộc tính được bảo vệ có vẻ như nó sẽ hoạt động trong hầu hết các tình huống. Trong thực tế, có rất nhiều lần bạn sẽ muốn sử dụng getters và setters của mình khi truy cập vào các thuộc tính trong định nghĩa lớp và các lớp mở rộng. Một giải pháp tốt hơn là một lớp cơ sở và giao diện khi mở rộng các lớp khác, vì vậy bạn có thể chỉ cần sao chép một vài dòng mã từ lớp cơ sở vào lớp thực thi. Tôi đang làm nhiều hơn một chút với lớp cơ sở của dự án của mình, vì vậy tôi không có giao diện để cung cấp ngay bây giờ, nhưng đây là định nghĩa lớp đã rút gọn chưa được thử nghiệm với việc nhận và thiết lập thuộc tính ma thuật bằng cách sử dụng phản chiếu để xóa và di chuyển các thuộc tính đến một mảng được bảo vệ:
class Component {
protected $properties = array();
public function __get($name) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
return $this->properties[$name]->value;
}
}
public function __set($name, $value) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
$this->properties[$name]->value = $value;
}
}
function __construct() {
$reflected_class = new ReflectionClass($this);
$properties = array();
foreach ($reflected_class->getProperties() as $property) {
if ($property->isStatic()) { continue; }
$properties[$property->name] = (object)array(
'name' => $property->name, 'value' => $property->value
, 'access' => $property->getModifier(), 'class' => get_class($this));
unset($this->{$property->name}); }
$this->properties = $properties;
}
}
Tôi xin lỗi nếu có bất kỳ lỗi nào trong mã.