2010-09-14 29 views
6

Xin chào tôi cần chỉ nhận các phương thức được khai báo trong một lớp, chứ không phải các phương thức được kế thừa. Tôi cần cái này cho CakePHP. Tôi đang nhận được tất cả các bộ điều khiển, tải chúng và lấy các phương thức từ các bộ điều khiển đó. Nhưng không chỉ là những phương thức được khai báo, mà còn là các phương thức được thừa kế.Chỉ nhận các phương thức được khai báo của một lớp trong PHP

Có phương pháp nào để chỉ nhận các phương thức được khai báo hay không.

+0

Tôi không biết phương pháp nào ngoại trừ các công cụ phản chiếu phức tạp. Bạn cần cái này để làm gì? –

+0

Bạn có thể cho tôi biết lý do bạn làm việc này không? Có phải tài liệu hoặc để sử dụng trong ứng dụng không? –

+0

Tôi cần phải thêm tất cả các phương thức công khai trong bộ điều khiển vào bảng quyền của mình. Tôi đang sử dụng CakePHP, và thành phần ACL của họ không hoạt động với mô hình hiện tại mà tôi có. – macha

Trả lời

9

Bạn có thể làm điều này (mặc dù hơn một chút so với "đơn giản") với ReflectionClass

function getDeclaredMethods($className) { 
    $reflector = new ReflectionClass($className); 
    $methodNames = array(); 
    $lowerClassName = strtolower($className); 
    foreach ($reflector->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { 
     if (strtolower($method->class) == $lowerClassName) { 
      $methodNames[] = $method->name; 
     } 
    } 
    return $methodNames; 
} 
+0

tại sao bạn sử dụng 'ReflectionMethod :: IS_PUBLIC'? – chelmertz

+0

Để giới hạn nó chỉ với phương pháp công khai. Nếu bạn muốn tất cả các phương pháp, chỉ cần bỏ qua ... – ircmaxell

+0

Nó nên được đề cập mặc dù, vì nó làm cho câu trả lời không đầy đủ cho câu hỏi. – chelmertz

1

Từ quan điểm kiến ​​trúc, tôi nghĩ rằng nên tránh phản chiếu nếu có thể, nhưng hãy xem ReflectionClass->getMethods() nếu bạn nghĩ mình biết mình đang làm gì.

<?php 

class A { 
    public function x() { } 
    public function y() { } 
} 

class B extends A { 
    public function a() { } 
    public function b() { } 
    public function x() { } // <-- defined here 
} 

$r = new ReflectionClass('B'); 
print_r($r->getMethods()); 

?> 

Bạn sẽ nhận được một danh sách các phương pháp xác định bởi BA, cùng với lớp mà cuối cùng định nghĩa nó. Đây là kết quả:

Array 
(
    [0] => ReflectionMethod Object 
     (
      [name] => a 
      [class] => B 
     ) 

    [1] => ReflectionMethod Object 
     (
      [name] => b 
      [class] => B 
     ) 

    [2] => ReflectionMethod Object 
     (
      [name] => x 
      [class] => B 
     ) 

    [3] => ReflectionMethod Object 
     (
      [name] => y 
      [class] => A 
     ) 

) 
+0

"Từ quan điểm kiến ​​trúc, tôi nghĩ rằng nên tránh phản chiếu nếu có thể" tại sao vậy? – chelmertz

+2

Hm, tôi đoán đó là sở thích cá nhân. Đối với tôi, sự phản chiếu tương tự như việc vá các tập tin thực thi trong bộ nhớ và * có thể * bất ngờ (hoặc phơi bày hành vi như vậy) trừ khi có tài liệu tốt và có thể làm cho mã của bạn phức tạp hơn hoặc giới thiệu các tác dụng phụ. Tuy nhiên, nó có thể hữu ích cho việc viết các khuôn khổ và lập trình meta/mở rộng các tính năng của ngôn ngữ. – Archimedix

0

đi qua một bình luận: "ReflectionClass :: getMethods() sắp xếp các phương pháp theo lớp (thấp nhất trong cây thừa kế trước) theo thứ tự chúng được định nghĩa trong định nghĩa lớp "ở đây - http://php.net/manual/en/reflectionclass.getmethods.php#115197

Tôi đã xác minh điều này và dường như là đúng. Dựa trên thực tế, chúng tôi có thể thêm một chút tối ưu hóa vào giải pháp của ircmaxell để tránh lặp lại các phương pháp kế thừa khác. Ngoài ra, thêm một số dọn dẹp để tránh constructor \ destructor:

public function getMethods($className) 
{ 
    $methodNames = []; 
    $reflectionClass = new ReflectionClass(className); 
    $publicMethods = $reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC); 
    $lowerClassName = strtolower($className); 
    foreach ($publicMethods as $method) { 
     if (strtolower($method->class) == $lowerClassName) { 
      // You can skip this check if you need constructor\destructor 
      if (!($method->isConstructor() || 
       $method->isDestructor())) { 
       $methodNames[] = $method->getName(); 
      } 
     } else { 
      // exit loop if class mismatch 
      break; 
     } 
    } 
    return $methodNames; 
} 
Các vấn đề liên quan