2013-06-06 26 views
13

Có cách nào trong PHP để nói (lập trình, rõ ràng) nếu một lớp nhất định là một nội bộ lớp (như DateTime) hoặc một lớp dùng (class MyClass)? Trong trường hợp bạn tự hỏi (và tôi chắc chắn bạn làm), điều này là bởi vì ReflectionClass::newInstanceWithoutConstructor() ném một ngoại lệ khi được sử dụng trên các lớp nội bộ, và khi tôi đang viết một thư viện để các đối tượng bản sao sâu, nó phải bỏ qua những nội bộ các lớp học.Làm cách nào để biết một lớp là lớp nội bộ hay lớp người dùng?

Có, tôi chỉ có thể bắt được ReflectionException, nhưng ngoại lệ này cũng được ném vì các lý do khác (chẳng hạn như một lớp không tồn tại) và không được ném cho tất cả các lớp hệ thống. vì vậy nó không hoàn thành chính xác nhu cầu của tôi.

+1

Tại sao chính xác một người muốn bỏ qua một nhà xây dựng? –

+1

@Cobra_Fast: Bạn sẽ không bao giờ muốn làm điều đó trong việc viết mã hàng ngày. Nhưng các thư viện làm điều đó để hydrate các đối tượng được tải từ một lưu trữ liên tục, hoặc trong trường hợp của tôi, để sao chép sâu một đối tượng đã được khởi tạo. – Benjamin

+0

Thậm chí nếu tôi định cư nó với dữ liệu ngoài, việc chạy hàm tạo không thể sai IMHO. Bạn không bao giờ có thể biết được những loại cấu trúc bên trong nào cần được khởi tạo. –

Trả lời

14

Một giải pháp sạch hơn so với sử dụng shell_exec whould được sử dụng phản ánh:

$reflection = new ReflectionClass('SomeClass'); 
if($reflection->isUserDefined()) { 
    // 'SomeClass' is not an PHP internal 
} 

Thay vì một chuỗi ('SomeClass') bạn cũng có thể vượt qua một đối tượng. Để biết thêm thông tin tra cứu ReflectionReflectionClass::isUserDefined() trong Hướng dẫn sử dụng PHP

+1

Ồ, đẹp! Người ta có thể 'array_filter' trên' get_declared_classes' và lấy danh sách tốt đẹp của các lớp do người dùng định nghĩa theo cách đó –

+4

Vì anh ta đã tạo ra một reflectionClass, đây rõ ràng là giải pháp tốt nhất. – h2ooooooo

+0

Woah, tôi đã bỏ lỡ giải pháp rõ ràng này. Đây là một. Cảm ơn bạn! – Benjamin

3

Thú vị câu hỏi, một trong những cách tôi có thể nghĩ là bằng cách kiểm tra tên miền không gian, ví dụ tất cả các lớp học của bạn sẽ được xác định dưới namespace MyApp và sau đó kiểm tra:

if(class_exists('\\DateTime')){ 
    continue; 
} 

Loại xấu xí, tôi biết.

+0

Tôi đã nghĩ về điều này và mặc dù tất cả các lớp * my * đều không có tên, nhưng tôi không thể đảm bảo rằng không ai sẽ cố gắng sử dụng mã này trên các lớp không có tên không may. – Benjamin

0

Bạn sẽ có thể bắt chước các hành vi phản ánh bằng cách mở rộng các lớp học mà bạn đang cố gắng để sao chép, và trọng __construct chức năng:

<?php 
    class MyClass extends ExtendingClass { 
     public function __construct() { 
      /* Override default constructor */ 
     } 
    } 
?> 

Mà về cơ bản có thể được thực hiện bằng cách sử dụng động eval:

<?php 
    function newInstanceWithoutConstructor($class) { 
     $className = $class . "Extended" . rand(0, 99999999); 
     while (class_exists($className)) { 
      $className = $class . "Extended" . rand(0, 99999999); 
     } 
     eval("class " . $className . " extends " . $class . " { public function __construct() { } }"); 
     return new $className(); 
    } 
    $newInstance = newInstanceWithoutConstructor("DateTime"); 
?> 

HOWEVER: Sử dụng eval có thể hữu ích trong trường hợp này, nhưng cũng cho thấy lỗ hổng bảo mật khá lớn nếu có thể gửi bất kỳ nội dung nào mà người dùng gửi bất kỳ cách nào để thay đổi nội dung của $class. Nếu bạn hiểu những hạn chế này và các tác động bảo mật, bạn sẽ có thể sử dụng điều này.

+0

Cảm ơn, nhưng tôi không muốn * khởi tạo * lớp nội bộ này bằng mọi giá, tôi chỉ muốn * bỏ qua * nếu nó xảy ra ở đó. – Benjamin

0

Bạn không thể sử dụng get_declared_classes() khi bắt đầu tập lệnh, lưu trữ dữ liệu trong một mảng và sau đó thực hiện array_diff() với dữ liệu đã lưu và phản hồi từ get_declared_classes() và kiểm tra xem lớp bạn đang kiểm tra có khác biệt không sử dụng in_array()?

+1

Bạn đã thử nghiệm chưa? Nó sẽ chứa các lớp *** được khai báo từ tất cả các tập lệnh. – BlitZ

+3

Tôi không thể kiểm soát khi mã của tôi sẽ được thực hiện (nó là một thư viện độc lập), vì vậy tại thời điểm tôi gọi 'get_declared_classes()', nó có thể đã chứa các lớp người dùng không may! – Benjamin

0

example in tất cả các lớp học với các lớp học của bạn dường như nằm ở cuối danh sách. Có lẽ điều này có thể giúp.

+0

Thật không may 'get_declared_classes()' cũng trả về các lớp người dùng! – Benjamin

+0

Vâng, nhưng chúng ở rất cuối (= không được sắp xếp theo tên của chúng), vì vậy có lẽ bạn chỉ có thể tìm nạp chúng ở cuối. Xin lỗi nếu nó không hữu ích: | –

0

Điều gì về việc lưu trữ calling get_declared_classes() dữ liệu trước khi bất kỳ tự động tải/bao gồm/yêu cầu nào được thực hiện và sau đó kiểm tra tên lớp trong bộ nhớ này?

+0

Nhận xét tương tự như đối với Дамян Станчев: Tôi sợ tôi không thể kiểm soát khi mã của tôi sẽ được thực hiện vì nó là một thư viện độc lập! – Benjamin

2

Thực phẩm cho tư tưởng, dựa trên gợi ý Дамян Станчев của:

Bạn chỉ có thể chạy một thông dịch viên PHP qua shell_exec() rằng sẽ phun ra get_declared_classes(). Nắm bắt đầu ra của điều đó và bạn cần phải có danh sách các lớp hệ thống "sạch".


Mở rộng câu trả lời Mogria, người ta điều này sẽ chỉ làm việc tốt (không cho tôi tín dụng cho điều này tuy nhiên, như nó đã được trả lời Mogria rằng đã làm đúng ;-)):

function getUserDefinedClasses() { 
    return array_filter(get_declared_classes(), 
         function ($class) { 
          $reflectionClass = new ReflectionClass($class); 
          return $reflectionClass->isUserDefined(); 
         }); 
} 
+1

Giải pháp tốt, chỉ vấn đề tôi có thể thấy với điều đó là nó dựa vào 'shell_exec' mà một số hệ thống có thể ngăn chặn. – Prisoner

+1

Điều đó sẽ hiệu quả. Một chút cồng kềnh, mặc dù, IMHO;) – Benjamin

Các vấn đề liên quan