2009-08-31 11 views
12

मैं अभी php के autoload() फ़ंक्शन को देख रहा हूं। एक अच्छा विचार लगता है, लेकिन मुझे यकीन नहीं है कि यह एकाधिक निर्देशिकाओं को कैसे संभालता है। मेरे वर्तमान विकास में मूल रूप से एक पुस्तकालय निर्देशिका संरचना समूह को कक्षाओं द्वारा उपनिर्देशिका में ऑपरेशन द्वारा वर्गीकृत किया गया है। मुझे आश्चर्य है कि मुझे प्रत्येक निर्देशिका के लिए एक शामिल() घोषित करना है ... जो मुझे उम्मीद है कि मुझे ऐसा करने की ज़रूरत नहीं है।ऑटोलोड और एकाधिक निर्देशिका

सलाह दे सकते हैं - धन्यवाद

उत्तर

1

दुर्भाग्य से, आप स्पष्ट रूप से प्रत्येक निर्देशिका जोड़ने के लिए है। यह या तो एक स्क्रिप्ट में प्रोग्रामेटिक रूप से किया जा सकता है जो आपकी निर्देशिकाओं को दोबारा घुमाता है, या आप एक सूची निर्दिष्ट कर सकते हैं।

शायद सबसे प्रभावी तरीका निर्देशिकाओं और उपनिर्देशिकाओं की एक सूची निर्दिष्ट करने के लिए है, और इन्हें ini_set() का उपयोग करके अपने 'include_path' में जोड़ें।

17

आप कक्षा नामों के लिए PEAR Convention पर एक नज़र डालना चाहते हैं, जो ऑटोलोडिंग के लिए वास्तव में बहुत अच्छा है।

असल में, यह कहा गया है कि:

नाशपाती वर्ग पदानुक्रम भी वर्ग के नाम में परिलक्षित, पदानुक्रम एक भी अंडरस्कोर के साथ अलग से प्रत्येक स्तर है।

फ़ाइल खोजने एक classe नाम HTML_Upload_Error के लिए शामिल करने के लिए इसका मतलब है '/' से की जगह '_' का मामला है, आप HTML/Upload/Error.php

अधिक स्पष्टीकरण के लिए, और उदाहरण के एक जोड़े दे रही है, आप लेख पर एक नज़र ले जा सकते हैं:

Btw: इस सम्मेलन द्वारा किया जाता है कई बड़े फ्रेमवर्क/पुस्तकालय ;-)
उदाहरण के लिए, ज़ेंड फ्रेमवर्क इस सम्मेलन का उपयोग करता है - और यह वास्तव में सहायक है!

+0

मुझे इस विधि को बहुत अच्छी तरह से काम करने के लिए मिला है। मैंने उपयोग की एक और विधि फ़ोल्डर मैप में स्थिर पैकेज का उपयोग करना है, जो रूट-निर्देशिकाओं को इंगित करता है जिसके अंतर्गत उपर्युक्त विधि लागू होती है। महान स्पष्टीकरण लिंक के लिए –

+2

+1 जो __autoload को बहुत अच्छी तरह से समझाता है: http://blog.straylightrun.net/2009/05/06/autoload-magic/ –

1

आप उलझन में लगते हैं :) या शायद मैं आपके प्रश्न से उलझन में हूं।

कक्षा में ढूंढने और लोड करने वाले फ़ंक्शन को लिखने के लिए यह पूरी तरह से निर्भर है, PHP इस पर ध्यान नहीं देता कि यह कितना स्तर गहरा है।

और, SPL autoload too पर देखें, इसकी समान आधार कार्यक्षमता है, लेकिन आप एकाधिक ऑटोलोड फ़ंक्शन लिख सकते हैं और फिर उन्हें चेन कर सकते हैं। उपयोगी हो सकता है, अगर आप कुछ बाहरी पुस्तकालयों का उपयोग करना चाहते हैं, जो अपने स्वयं के ऑटोलोडर को परिभाषित करते हैं जो संभवतः आपके साथ संघर्ष कर सकते हैं।

1

मुझे लगता है कि आप PHP की एसपीएल ऑटोलोड क्षमता के बारे में बात कर रहे हैं - जहां आप लिखते हैं कि आप अपना कार्य हैं और फिर इसे एसपीएल के साथ पंजीकृत करें।

आप यह कैसे करते हैं इस पर निर्भर करता है कि आप अपने शामिल फ़ंक्शन कैसे बनाते हैं। कई शामिल फ़ंक्शंस घोषित करना संभव है और फिर उन्हें PHP के साथ पंजीकृत करें: आप पर कितने निर्भर हैं। एसपीएल ऑटोलोड लोड करने की क्षमता आपको बस अपना स्वयं का फ़ंक्शन बनाने की अनुमति देती है और फिर प्रत्येक बार कक्षा की आवश्यकता होने पर उस फ़ंक्शन को चलाने के लिए PHP को बताती है।

एकाधिक बनाने का एक लाभ उन्हें उपयोग के क्रम में पंजीकृत करने की क्षमता है, सबसे पहले उपयोग की जाने वाली निर्देशिका सबसे पहले कम से कम उपयोग की जाती है। साथ ही, यदि कोई निर्देशिका बदली जाती है या हटा दी जाती है, तो आप ज़िम्मेदार फ़ंक्शन को सरल परिवर्तन और/या हटा देते हैं।

आप एक ऐसा फ़ंक्शन लिख सकते हैं जो आपके द्वारा पूरी फ़ोल्डर संरचना भी हो जाएगा (हालांकि मैं इसे प्रशासन और कोड decoupling की आसानी के लिए अनुशंसा नहीं करता)। ऐसा करने के लिए कोई "तकनीकी रूप से सही" तरीका नहीं है :)

10

यहां एक वर्ग है जिसे मैंने कुछ समय पहले इसी उद्देश्य के लिए लिखा था। उस समय मैं अभी भी सीखने के चरण में था, इसलिए बेवकूफ विचार शामिल हो सकते हैं; यह फिर भी काम किया।

मूल विचार यह है कि यह एक बार स्रोत निर्देशिका स्कैन करता है, और अपनी स्रोत फ़ाइलों में सरणी मैपिंग कक्षाएं बनाता है। कक्षा एक ऑटोलोडर के रूप में पंजीकृत है, और जब लागू किया जाता है, इसमें आवश्यक फ़ाइल शामिल होती है। यदि नहीं मिला, तो यह फ्लाई पर सरणी को पुनर्निर्माण करने का प्रयास करता है।

/* register ClassLoader as class loader */ 
spl_autoload_register(array(ClassLoader::getInstance(), 'loadClass')); 


class ClassLoader { 

    private static $SAVE_FILE = 'ClassLoader.save.php'; 

    /* singleton */ 
    private static $instance; 

    /* stores a className -> filePath map */ 
    private $classList; 
    /* tells whether working from saved file */ 
    private $refreshed; 


    public static function getInstance() { 
     if (!isset(self::$instance)) { 
      self::$instance = new ClassLoader(); 
     } 
     return self::$instance; 
    } 

    private function __construct() { 
     $this->initClassList(); 
    } 

    public function loadClass($className) { 
     if (!array_key_exists($className, $this->classList) && !$this->refreshed) { 
      $this->refreshClassList(); 
     } 
     require_once($this->classList[$className]); 
    } 

    private function initClassList() { 
     if (file_exists(INCLUDES_DIR . self::$SAVE_FILE)) { 
      require_once(INCLUDES_DIR . self::$SAVE_FILE); 
      $this->refreshed = FALSE; 
     } else { 
      $this->refreshClassList(); 
     } 
    } 

    private function refreshClassList() { 
     $this->classList = $this->scanDirectory(INCLUDES_DIR); 
     $this->refreshed = TRUE; 

     $this->saveClassList(); 
    } 

    private function saveClassList() { 
     $handle = fopen(INCLUDES_DIR . self::$SAVE_FILE, 'w'); 
     fwrite($handle, "<?php\r\n"); 

     foreach($this->classList as $class => $path) { 
      $line = '$this->classList' . "['" . $class . "'] = '" . $path . "';\r\n"; 
      fwrite($handle, $line); 
     } 

     fwrite($handle, '?>'); 
     fclose($handle); 
    } 

    private function scanDirectory ($directory) { 
     // strip closing '/' 
     if (substr($directory, -1) == '/') { 
      $directory = substr($directory, 0, -1); 
     } 

     if (!file_exists($directory) || !is_dir($directory) || !is_readable($directory)) { 
      return array(); 
     } 

     $dirH = opendir($directory); 
     $scanRes = array(); 

     while(($file = readdir($dirH)) !== FALSE) { 

      // skip pointers 
      if (strcmp($file , '.') == 0 || strcmp($file , '..') == 0) { 
       continue; 
      } 

      $path = $directory . '/' . $file; 

      if (!is_readable($path)) { 
       continue; 
      } 

      // recursion 
      if (is_dir($path)) { 
       $scanRes = array_merge($scanRes, $this->scanDirectory($path)); 

      } elseif (is_file($path)) { 
       $className = explode('.', $file); 
       if (strcmp($className[1], 'class') == 0 && strcmp($className[2], 'php') == 0) { 
        $scanRes[$className[0]] = $path; 
       } 
      } 
     } 

     return $scanRes; 
    } 

} 
+0

कमाल क्लासलोडर। – Jerska

1

पहले से ही उल्लेख किया है, एसपीएल autoloading कार्यात्मक एक संरचना है जिन पर आप व्यावहारिक कार्यान्वयन भ्रष्टाचार के लिए है - निर्देशिका ट्रावर्सल और नामकरण सम्मेलनों उन विचारों का हिस्सा हैं।

ज़ेंड लोडर के रूप में एक व्यावहारिक उदाहरण लें: इसके आधार पर, यह एक सिंगलटन है जो PHP के शामिल पथ के साथ पंजीकृत निर्देशिकाओं के लिए नामस्थानों से संबंधित सम्मेलन का एक सम्मेलन का उपयोग करता है। प्रैक्टिकल उदाहरण:

set_include_path(get_include_path(). PATH_SEPARATOR. 'App/'); //Concat the "App" directory onto the existing include paths 
$loader = Zend_Loader::getInstance(); //because the autoloader is a singleton, we get a reference to it without assuming we need to first create it 
$loader->registerNamespace('App_'); //Tell autoloader it can look in the app directory to find classes if it can't find them in the default Zend directory. 

जाहिर विशिष्ट कार्यान्वयन चिंताओं परियोजना के लिए, दोनों और समझ में एक अभ्यास के रूप में कोड पुनः उपयोग के लिए एक autoloader कि एक पार्स कर सकते हैं प्रोग्रामिंग पर अपने हाथ आजमाने का परियोजना से अलग अलग होंगे, लेकिन यह सबसे अच्छा हो सकता है, विशिष्ट श्रेणी प्रारूप (जैसे 'directory_classname') को एक निर्देशिका मानचित्र में, फिर कक्षा को लोड और मान्य करें।

संबंधित मुद्दे