2013-07-23 6 views
5

Tôi đã thử nghiệm với các kỹ thuật lập bản đồ thư mục lớp tự động tải, và nó đã là một chút của một cuộc đấu tranh. Tôi đã tìm ra một giải pháp khá đơn giản (trên bề mặt), nhưng tôi hoàn toàn băn khoăn rằng nó hoạt động cả, trong khi các giải pháp "rõ ràng hơn" không thành công. Dưới đây là một số đoạn mã minh họa sự nhầm lẫn của tôi.Trình tải tự động của php: tại sao tính năng này hoạt động?

Dưới đây là đoạn code làm việc:

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     $classMap = array(
      'classes/', 
      'classes/sites/', 
      'classes/data/' 
     ); 
     foreach ($classMap as $location) { 
      if ([email protected]_once($location . $class . '.php')) { // @ SUPPRESSES include_once WARNINGS 
       // CLASS DOESN'T EXIST IN THIS DIRECTORY 
       continue; 
      } else { 
       // CLASS IS AUTO-LOADED 
       break; 
      } 
     } 
    } 
?> 

Dưới đây là một đoạn mà tôi cảm thấy nên làm việc, nhưng không:

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     $classMap = array(
      'classes/', 
      'classes/sites/', 
      'classes/data/' 
     ); 
     foreach ($classMap as $location) { 
      if (file_exists($location . $class . '.php')) { 
       require_once ($location . $class . '.php'); 
      } 
     } 
    } 
?> 

Sau đó có ý nghĩa hơn với tôi bởi vì trong khi hai phiên bản hoạt động:

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     require_once ('classes/sites/' . $class . '.php'); 
    } 
?> 

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) {     
     $location = 'classes/sites/';     
     require_once ($location . $class . '.php'); 
    } 
?> 

Điều này một lần ném "Không có tệp hoặc thư mục như vậy ..." (lưu ý thiếu "trang web /" trong đường dẫn.

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     require_once ('classes/' . $class . '.php'); 
    } 
?> 

Lỗi "Không có tệp hoặc thư mục ..." khiến tôi nghĩ rằng tôi có thể chỉ cần kiểm tra tệp hỗ trợ của lớp và, nếu (file_exists()) {require_once(); break;} else {continue;}

Tại sao tính năng này không hoạt động? Và, tại sao đoạn mã đầu tiên hoạt động? Đường dẫn/tệp hỗ trợ không bao giờ được bao gồm hoặc yêu cầu một cách rõ ràng.

+0

là thư mục mẹ của đường dẫn lớp trong include_paths của bạn? – Orangepill

+0

Tệp hỗ trợ IS được bao gồm, nó chỉ được kết hợp vào câu lệnh if: if (! @include_once ($ location. $ Class. '.php')) –

+0

Vâng, tôi đã nghĩ rằng, john500, nhưng đã hy vọng xác nhận , cảm ơn vì điều đó. Nó cảm thấy như một cách rất cẩu thả để đạt được những gì tôi cần, tuy nhiên, vì vậy điều này chỉ tăng gấp đôi ngứa của tôi để cải thiện các giải pháp. Orangepill, tôi không chắc chắn làm thế nào để làm điều đó ... Tôi đã không làm việc với PHP trong một thời gian, và khi tôi cuối cùng đã làm, tôi không phải là một nửa giỏi lập trình như tôi bây giờ ... vì vậy tôi về cơ bản hack PHP cố gắng để làm những điều tôi đã biết làm thế nào để làm trong Java và Coldfusion;). –

Trả lời

1

OK, tôi đã tìm ra. Vấn đề của tôi thực sự không thiết lập đường dẫn chính xác; sử dụng hằng số __DIR__ là đường dẫn :: ahem :: thành công. Dưới đây là đoạn code làm việc bây giờ tôi đang sử dụng:

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     $classMap = array(
      'classes/', 
      'classes/sites/', 
      'classes/data/' 
     ); 
     foreach ($classMap as $location) { 
      if (file_exists(__DIR__ . '/' . $location . $class . '.php')) { 
       require_once(__DIR__ . '/' . $location . $class . '.php'); 
       break; 
      } 
     } 
    } 
?> 

Hóa ra __DIR__ trả về vị trí thư mục của tập tin thực tế, trong đó nó được gọi là (như trái ngược với, chẳng hạn, một tập tin đó là bao gồm nó), mà có nghĩa là điều này sẽ làm việc miễn là tệp này vẫn nằm trong thư mục gốc của thư mục với thư mục/classes của tôi. Và, nó tồn tại độc quyền để xác định các loại cài đặt này ...

Hy vọng điều này sẽ giúp người khác xuống hàng! Và, tất nhiên, nếu bất cứ ai có thể làm sáng tỏ lý do tại sao giải pháp này là tối ưu, tôi là tất cả các mắt ...

EDIT: Một tối ưu hóa tôi sẽ thực hiện sẽ chuyển đổi $ classMap array() để một mảng kết hợp (ví dụ ,. $classMap = array('root' => 'classes/', 'sites' => 'classes/sites/'); vì vậy tôi có thể làm một tra cứu hơn là lặp qua tất cả các thư mục tôi tạo theo thời gian Nhưng, tôi cho rằng đó là cho thread khác

EDIT2:.. Nếu có ai quan tâm, đây là Về cơ bản, tôi đã thiết lập một mảng kết hợp trong $ GLOBALS và sử dụng nó để lưu trữ một bản đồ của các lớp -> Các gói. Sau đó, trong trình nạp tự động, tôi ánh xạ các gói -> Các vị trí và sau đó gọi trong tập tin cần thiết cho lớp instantiated.

Đây là tập tin cấu hình toàn cầu:

<?php 
    // INITIALIZE GLOBAL Class -> Package map 
    if (!array_key_exists('packageMap',$GLOBALS)) { 
     $GLOBALS['packageMap'] = array(); 
    } 

    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     $classMap = array(
      'root'=>'/classes/', 
      'sites'=>'/classes/sites/', 
      'data'=>'/classes/data/' 
     ); 

     // RESOLVE MAPPINGS TO AN ACTUAL LOCATION 
     $classPackage = $GLOBALS['packageMap'][$class]; 
     $location = $classMap[$classPackage]; 
     if (file_exists(__DIR__ . $location . $class . '.php')) { 
      require_once(__DIR__ . $location . $class . '.php'); 
     } 
    } 
?> 

Đây là một trang web tập tin cấu hình cụ thể mà sử dụng autoloader:

<?php 
    // LOAD GLOBAL CONFIG FILE  
    require_once('../config/init.php'); 

    // CREATE LOCAL REFERENCE TO GLOBAL PACKAGE MAP (MOSTLY FOR READABILITY) 
    $packageMap = $GLOBALS['packageMap']; 

    // ADD Class -> Package MAPPINGS 
    $packageMap['DAO'] = 'data'; 
    $packageMap['SomeSite'] = 'sites'; 
    $packageMap['PDOQuery'] = 'data'; 

    // INSTANTIATE SOMETHING IN ONE OF THE PACKAGES 
    $someSite = new SomeSite(); 
?> 

Hy vọng rằng đây là hữu ích cho người khác ...nếu nó tăng bất kỳ cờ đỏ cho bất cứ ai, xin vui lòng kêu vang. Cuối cùng, tôi muốn thay thế việc sử dụng $ GLOBALS với apc, nhưng nó không được cài đặt trên máy chủ lưu trữ của tôi: /. Tôi có thể xem xét memcached, nhưng tôi đã nghe đánh giá hỗn hợp ...

+0

Bạn cũng có thể sử dụng ['__DIR__'] (http://php.net/manual/en/language.constants.predefined.php) như của PHP 5.3 – Raekye

+0

Ah có, thậm chí tốt hơn ... cảm ơn. Mã giải pháp được cập nhật. –