Tôi đang sử dụng __get() để làm cho một số thuộc tính của tôi "động" (chỉ khởi tạo chúng khi được yêu cầu). Các thuộc tính "giả" này được lưu trữ bên trong một thuộc tính mảng riêng tư, mà tôi đang kiểm tra bên trong __get.Sử dụng __get() (ma thuật) để mô phỏng tính thích hợp chỉ đọc và tải chậm
Dù sao, bạn có nghĩ rằng tốt hơn nên tạo phương pháp cho mỗi trong số các proprties này thay vì làm nó trong một tuyên bố chuyển đổi?
Chỉnh sửa: kiểm tra tốc độ
Tôi chỉ quan tâm đến hiệu suất, công cụ khác mà @Gordon đề cập không phải là quan trọng với tôi:
- không cần thiết thêm phức tạp - nó không thực sự tăng mức độ phức tạp của ứng dụng của tôi
- API không rõ ràng dễ vỡ - Tôi đặc biệt muốn API của mình bị "cách ly"; Các tài liệu nên nói cho người khác làm thế nào để sử dụng nó: P
Vì vậy, đây là những bài kiểm tra mà tôi đã làm, mà làm cho tôi nghĩ rằng hiệu suất hit agument là phi lý:
Kết quả cho 50.000 cuộc gọi (trên PHP 5.3 .9):
(t1 = ma thuật với switch, t2 = getter, t3 = ma thuật với cuộc gọi getter thêm)
Không chắc những gì các "Cum" điều có ý nghĩa trên t3. Nó không thể là thời gian tích lũy vì t2 nên có 2K rồi ...
Mã:
class B{}
class A{
protected
$props = array(
'test_obj' => false,
);
// magic
function __get($name){
if(isset($this->props[$name])){
switch($name){
case 'test_obj':
if(!($this->props[$name] instanceof B))
$this->props[$name] = new B;
break;
}
return $this->props[$name];
}
trigger_error('property doesnt exist');
}
// standard getter
public function getTestObj(){
if(!($this->props['test_obj'] instanceof B))
$this->props['test_obj'] = new B;
return $this->props['test_obj'];
}
}
class AA extends A{
// magic
function __get($name){
$getter = "get".str_replace('_', '', $name); // give me a break, its just a test :P
if(method_exists($this, $getter))
return $this->$getter();
trigger_error('property doesnt exist');
}
}
function t1(){
$obj = new A;
for($i=1;$i<50000;$i++){
$a = $obj->test_obj;
}
echo 'done.';
}
function t2(){
$obj = new A;
for($i=1;$i<50000;$i++){
$a = $obj->getTestObj();
}
echo 'done.';
}
function t3(){
$obj = new AA;
for($i=1;$i<50000;$i++){
$a = $obj->test_obj;
}
echo 'done.';
}
t1();
t2();
t3();
ps: tại sao tôi muốn sử dụng __get() trong phương pháp getter tiêu chuẩn? lý do duy nhất là vẻ đẹp api; vì tôi không thấy bất kỳ bất lợi thật, tôi đoán nó có giá trị nó: P
Edit: Nhiều bài kiểm tra tốc độ
thời gian này tôi đã sử dụng microtime để đo lường một số trung bình:
PHP 5.2. 4 và 5.3.0 (kết quả tương tự):
t1 - 0.12s
t2 - 0.08s
t3 - 0.24s
PHP 5.3.9, với Xdebug tích cực này là lý do tại sao nó rất chậm:
t1 - 1.34s
t2 - 1.26s
t3- 5.06s
PHP 5.3.9 với Xdebug bị vô hiệu hóa:
t1 - 0.30
t2 - 0.25
t3 - 0.86
Một phương pháp:
// magic
function __get($name){
$getter = "get".str_replace('_', '', $name);
if(method_exists($this, $getter)){
$this->$name = $this->$getter(); // <-- create it
return $this->$name;
}
trigger_error('property doesnt exist');
}
Một tài sản công cộng với tên yêu cầu sẽ được tạo ra tự động sau khi cuộc gọi __get đầu tiên. Điều này giải quyết các vấn đề về tốc độ - nhận được 0.1s trong PHP 5.3 (nhanh hơn 12 lần so với getter tiêu chuẩn) và vấn đề mở rộng do Gordon đưa ra. Bạn có thể chỉ cần ghi đè lên getter trong lớp con.
Điểm bất lợi là bất động sản trở nên ghi :(
Trong các thử nghiệm này, "cum" là lượng thời gian mà hàm đã thực hiện, bao gồm thời gian của bất kỳ hàm nào được gọi từ bên trong (về cơ bản đó là lượng thời gian thực tế từ khi hàm bắt đầu thực hiện cho đến khi hàm đó trả về). Điều này khác với thời gian "tự", có hiệu quả "tạm dừng" bộ hẹn giờ khi các chức năng khác được gọi. Trong trường hợp này, "cum" trừ "self" cho t3 hoạt động ra bao nhiêu thời gian đã được chi tiêu trong $ this -> $ getter() gọi, và "tự" là bao lâu nó đã cho nó để làm những thứ khác trong hàm __get(). –