Hindi (हिंदी) translation by Ashish Rampal (you can also view the original English article)
कईं बार हम चीजों को बहुत हल्के में लेते हैं. अगर कुछ अपेक्षा के अनुरूप काम कर रहा है, तो हम आंतरिक तंत्र (underlying mechanism) को समझने के लिए आंतरिक कार्यो (inner workings) के बारे में परेशान नहीं होते। या इसे दूसरे तरीके से समझते हैं, जब तक हमें कुछ परेशानी नहीं होती हम कुछ सीख नहीं सकते.!
इसी तरह, मैं हमेशा OpenCart में कुछ अवधारणाओं (concepts) के बारे में सोच रहा था जिसका उपयोग अंतर्निहित ढांचे (underlying framework) में किया गया था, और इनमें से एक प्रॉक्सी क्लास (proxy class) था। इसे समझने में मुझे कुछ समय लगा, और मैंने सोचा कि यह आपके साथ साझा करने के लिए बहुत अच्छी चीज है क्योंकि कुछ नया जानना हमेशा मजेदार होता है.
प्रॉक्सी क्लास क्या है?
यद्यपि आप ऑनलाइन, प्रॉक्सी को परिभाषित करने वाली विभिन्न सामग्रियों (various materials) को खोज लेंगे, विकिपीडिया की परिभाषा काफी ठीक और समझने में आसान है।
एक प्रॉक्सी, अपने सबसे सामान्य रूप में, एक क्लास है जो की इंटरफ़ेस (interface) से कुछ और के लिए कार्य (functioning) करती है।
इसलिए प्रॉक्सी ऑब्जेक्ट, जो इसे प्रयोग करना चाहता है, को कण्ट्रोल सौंप देता है, और इस प्रकार यह उस क्लास जो instantiate हुई है की ओर से कार्य करता है.। वास्तव में, प्रॉक्सी डिज़ाइन पैटर्न एक बहुत ही लोकप्रिय पैटर्न है, जो कि आवश्यक फ्रेमवर्कों द्वारा उपयोग की जाती है। इस तथ्य को ध्यान में रखते हुए कि अपने आप में प्रॉक्सी पद्धति की चर्चा एक व्यापक विषय है और इस लेख के दायरे से बाहर, मैं जल्दी से संक्षेप में बताऊंगा कि इसका अधिकांश समय किसलिए उपयोग किया जाता है:
- अतिरिक्त कार्यक्षमता प्रदान करने के लिए आवरण के रूप में कार्य करती है.
- मंहगे ऑब्जेक्ट्स के instantiation में विलम्ब करना जिसे lazy loading भी कहा जाता है।
OpenCart के संदर्भ में, हम कह सकते हैं कि प्रॉक्सी पैटर्न का इस्तेमाल बेस प्रॉक्सी क्लास में कार्यक्षमता जोड़ने के लिए किया जाता है। यह कहने के बाद, बेस प्रॉक्सी क्लास कुछ जादुई methods को छोड़कर कुछ भी नहीं प्रदान करता है! जैसा कि हम अगले भाग में देखेंगे, प्रॉक्सी क्लास रन-टाइम (run-time) पर प्रॉपर्टीज को जोड़ने में समृद्ध है.
हम अगले अनुभाग में जाने से पहले, चलो प्रॉक्सी क्लास पर एक जल्दी से नज़र डालें। यह system/engine/proxy.php
में रहता है
<?php class Proxy { public function __get($key) { return $this->{$key}; } public function __set($key, $value) { $this->{$key} = $value; } public function __call($key, $args) { $arg_data = array(); $args = func_get_args(); foreach ($args as $arg) { if ($arg instanceof Ref) { $arg_data[] =& $arg->getRef(); } else { $arg_data[] =& $arg; } } if (isset($this->{$key})) { return call_user_func_array($this->{$key}, $arg_data); } else { $trace = debug_backtrace(); exit('<b>Notice</b>: Undefined property: Proxy::' . $key . ' in <b>' . $trace[1]['file'] . '</b> on line <b>' . $trace[1]['line'] . '</b>'); } } }
जैसा कि आप देख सकते हैं, यह तीन जादुई methods को लागू करता है: __get ()
, __set ()
, और __call ()
। उनमें से, __call ()
method को अमल में लाना महत्वपूर्ण है, और हम इसमें जल्द ही वापस आएंगे.
मॉडल के साथ प्रॉक्सी क्लास कैसे काम करती है
इस खंड में, मैं समझाता हूँ कि वास्तव में एक कॉल जैसे- $this->model_catalog_category->getCategory($category_id)
अलग सोच से काम करता है
वास्तव में, कहानी निम्नलिखित स्टेटमेंट से शुरू होती है
$this->load->model('catalog/category');
बूटस्ट्रैपिंग के दौरान, OpenCart फ्रेमवर्क सभी जेनेरिक ऑब्जेक्ट्स को Registry
ऑब्जेक्ट में संग्रहीत करता है ताकि वे fetched किये जा सकें। इसके परिणामस्वरूप, $this->load
की call Loader
ऑब्जेक्ट को रजिस्ट्री से return देता है।
Loader
क्लास विभिन्न कंपोनेंट्स को लोड करने के लिए विभिन्न methods को प्रदान करता है, लेकिन हमें यहां model method में दिलचस्पी है। system/engine/loader.php
से model
method के snippet को जल्दी से निकालें।
public function model($route) { // Sanitize the call $route = preg_replace('/[^a-zA-Z0-9_\/]/', '', (string)$route); // Trigger the pre events $this->registry->get('event')->trigger('model/' . $route . '/before', array(&$route)); if (!$this->registry->has('model_' . str_replace(array('/', '-', '.'), array('_', '', ''), $route))) { $file = DIR_APPLICATION . 'model/' . $route . '.php'; $class = 'Model' . preg_replace('/[^a-zA-Z0-9]/', '', $route); if (is_file($file)) { include_once($file); $proxy = new Proxy(); foreach (get_class_methods($class) as $method) { $proxy->{$method} = $this->callback($this->registry, $route . '/' . $method); } $this->registry->set('model_' . str_replace(array('/', '-', '.'), array('_', '', ''), (string)$route), $proxy); } else { throw new \Exception('Error: Could not load model ' . $route . '!'); } } // Trigger the post events $this->registry->get('event')->trigger('model/' . $route . '/after', array(&$route)); }
उपर्युक्त उदाहरण को ध्यान में रखते हुए, $root
आर्गुमेंट (argument) का मान (value) catalog/category
है। सबसे पहले, $root
वैरिएबल (variable) का मूल्य (value) स्वच्छ किया जाता है, और इसके बाद यह before
event ट्रिगर करता है जिससे कि अन्य मॉड्यूल listeners $root
वैरिएबल के मूल्य को बदल सकें।
इसके बाद, यह रजिस्ट्री में अनुरोधित (requested) मॉडल ऑब्जेक्ट के अस्तित्व की जांच करता है। यदि रजिस्ट्री अनुरोधित ऑब्जेक्ट रखती है, तो आगे कोई प्रोसेस (process) की आवश्यकता नहीं है।
यदि वस्तु नहीं मिली है, तो इसे लोड करने के लिए एक दिलचस्प प्रक्रिया का अनुसरण करता है, और यह वह स्निपेट (snippet) है जिसे हम इस आलेख (article) के संदर्भ (context) में ढूंढ रहे हैं।
आरंभ करने के लिए, यह अनुरोधित मॉडल के फ़ाइल पाथ को तैयार करता है और यदि यह मौजूद है तो उसे लोड करता है।
... $file = DIR_APPLICATION . 'model/' . $route . '.php'; $class = 'Model' . preg_replace('/[^a-zA-Z0-9]/', '', $route); if (is_file($file)) { include_once($file); ... } ...
उसके बाद, यह Proxy
ऑब्जेक्ट को instantiate करता है
$proxy = new Proxy();
अब, अगले for
लूप पर ध्यान दें- यह जो है उससे बहुत अधिक दिखता है.
foreach (get_class_methods($class) as $method) { $proxy->{$method} = $this->callback($this->registry, $route . '/' . $method); }
हमारे मामले में, $class
की वैल्यू ModelCatalogCategory
होना चाहिए. get_class_methods ($class)
स्निपेट (snippet) ModelCatalogCategory
class के सभी methods को लोड करता है और इसके माध्यम से loops। यह लूप में क्या करता है? चलो बारीकी से देखें.
लूप में, यह एक ही class के callback
method को कॉल करता है। यह ध्यान रखना दिलचस्प है कि callback method फ़ंक्शन callable देता है जो method के नाम के रूप में key के साथ $proxy
ऑब्जेक्ट को असाइन करता है। बेशक, प्रॉक्सी ऑब्जेक्ट में ऐसी कोई प्रॉपर्टीज नहीं हैं; यह __set()
जादुई method का उपयोग करके हवा में (on the fly) बनाया जाएगा!
इसके बाद, $proxy
ऑब्जेक्ट को रजिस्ट्री में जोड़ा जाता है ताकि जरूरत पड़ने पर इसे बाद में लाया जा सके। set
method के प्रमुख कॉम्पोनेन्ट पर नज़दीकी नज़र रखते है। हमारे मामले में, यह model_catalog_category
होना चाहिए.
$this->registry->set('model_' . str_replace(array('/', '-', '.'), array('_', '', ''), (string)$route), $proxy);
अंत में, यह अन्य मॉड्यूल लिस्टनर्स (module listeners) को $route
वैरिएबल की वैल्यू को बदलने देने के लिए after
इवेंट कॉल करेगा।
यह कहानी का एक हिस्सा है.
चलो देखते हैं कि वास्तव में क्या होता है जब आप अपने कंट्रोलर में निम्नलिखित का उपयोग करते हैं।
$this->model_catalog_category->getCategory($category_id);
$this->model_catalog_category
स्निपेट (snippet), model_catalog_category
key के लिए रजिस्ट्री में एक मैच ढूंढने की कोशिश करता है। यदि आप सोच रहे हैं कि कैसे, बस system/engine/controller.php
फ़ाइल में Controller
class की परिभाषा देखें - यह करने के लिए यह एक जादुई method __get()
प्रदान करता है।
यह $proxy
ऑब्जेक्ट को return करेगा जो की उस विशिष्ट key को असाइन कर दिया जाएगा. इसके बाद, वह उस ऑब्जेक्ट पर getCategory
method को कॉल करने का प्रयास करता है। लेकिन Proxy क्लास ऐसा कोई method लागू नहीं करती है, तो यह कैसे काम करने जा रहा है?
__call()
जादुई method बचाव के लिए आता है! जब भी आप एक ऐसे method call करते हैं जो क्लास में मौजूद नहीं हो, कंट्रोल जादुई method __call()
को स्थानांतरित कर दिया जाता है.
चलिए इसे समझने के लिए विस्तार से देखें कि क्या हो रहा है। प्रॉक्सी क्लास फ़ाइल खोलें और उस method पर ध्यान दें।
$key
में फ़ंक्शन का नाम शामिल है जिसे- getCategory
कहा जाता है दूसरी ओर, $args
में method को पारित (pass) arguments है, और यह एक एलिमेंट जो की category id है और जिसे pass किया जाना है को होल्ड करने वाला एक array होना चाहिए.
इसके बाद, एक array $arg_data
है जो arguments के निर्देश (reference) संग्रहीत (store) करता है। सच कहूँ तो, मुझे यकीन नहीं है कि अगर $arg instanceof Ref
का कोई भी अर्थ है या नहीं. अगर कोई जानता है कि यह वहां क्यों है, तो मुझे सीखने में खुशी होगी।
इसके अलावा, यह $proxy
ऑब्जेक्ट में $key
की प्रॉपर्टी के अस्तित्व (existence) को देखने की कोशिश करता है, और इसका परिणाम कुछ ऐसा होता है।
if (isset($this->getCategory)) {
याद करें कि पहले हमने for
लूप का प्रायोड करके ModelCatalogCategory
class के सभी methods को $proxy
ऑब्जेक्ट में असाइन कर दिया था। आपकी सुविधा के लिए, मैं उस कोड को फिर से पेस्ट कर दूँगा
... foreach (get_class_methods($class) as $method) { $proxy->{$method} = $this->callback($this->registry, $route . '/' . $method); } ...
तो यह वहां होना चाहिए, और इसे callable फंक्शन को भी हमे return करना चाहिए! और अंत में, यह उस callable फंक्शन को call_user_func_array
फंक्शन को के प्रयोग से कॉल करता है जो की खुद callable फंक्शन और method आर्ग्यूमेंट्स को pass करता है।
अब, आइए हम callable function की परिभाषा पर ध्यान दें। मैं system/engine/loader.php
में परिभाषित callback
मेथड से स्निपेट को लूंगा।
... function($args) use($registry, &$route) { static $model = array(); $output = null; // Trigger the pre events $result = $registry->get('event')->trigger('model/' . $route . '/before', array(&$route, &$args, &$output)); if ($result) { return $result; } // Store the model object if (!isset($model[$route])) { $file = DIR_APPLICATION . 'model/' . substr($route, 0, strrpos($route, '/')) . '.php'; $class = 'Model' . preg_replace('/[^a-zA-Z0-9]/', '', substr($route, 0, strrpos($route, '/'))); if (is_file($file)) { include_once($file); $model[$route] = new $class($registry); } else { throw new \Exception('Error: Could not load model ' . substr($route, 0, strrpos($route, '/')) . '!'); } } $method = substr($route, strrpos($route, '/') + 1); $callable = array($model[$route], $method); if (is_callable($callable)) { $output = call_user_func_array($callable, $args); } else { throw new \Exception('Error: Could not call model/' . $route . '!'); } // Trigger the post events $result = $registry->get('event')->trigger('model/' . $route . '/after', array(&$route, &$args, &$output)); if ($result) { return $result; } return $output; }; ...
चूंकि यह एक अनाम फंक्शन है, उसने $registry
और $route
variables के रूप में वैल्यूज को संरक्षित कर लिया है जो पहले कॉलबैक विधि के लिए पारित किए गए थे। इस स्थिति में, $root
variable का मान catalog/category/getCategory
होना चाहिए।
इसके अलावा, अगर हम उस फंक्शन में महत्वपूर्ण स्निपेट (snippet) को देखते हैं, तो यह ModelCatalogCategory
ऑब्जेक्ट को instantiate करता है और उसे एक static $model
array में store करता है।
... // Store the model object if (!isset($model[$route])) { $file = DIR_APPLICATION . 'model/' . substr($route, 0, strrpos($route, '/')) . '.php'; $class = 'Model' . preg_replace('/[^a-zA-Z0-9]/', '', substr($route, 0, strrpos($route, '/'))); if (is_file($file)) { include_once($file); $model[$route] = new $class($registry); } else { throw new \Exception('Error: Could not load model ' . substr($route, 0, strrpos($route, '/')) . '!'); } } ...
और यहां एक स्निपेट है जो method के नाम को पकड़ता है जिसे $root
वैरिएबल का इस्तेमाल करने के लिए call किया जाना चाहिए।
$method = substr($route, strrpos($route, '/') + 1);
तो हमारे पास ऑब्जेक्ट रेफरेंस और एक method का नाम है जो हमें call_user_func_array
फ़ंक्शन के उपयोग से कॉल करने की अनुमति देता है। निम्नलिखित स्निपेट ऐसा ही करता है!
... if (is_callable($callable)) { $output = call_user_func_array($callable, $args); } else { throw new \Exception('Error: Could not call model/' . $route . '!'); } ...
विधि के अंत में, परिणाम $output
वेरिएबल के माध्यम से return होता है। और हाँ, यह कहानी का एक दूसरा हिस्सा है!
मैंने जानबूझकर प्री (pre) और पोस्ट (post) इवेंट कोड को नजरअंदाज किया है जो आपको कोर OpenCart मेथड्स को ओवरराइड करने की अनुमति देता है। इसका उपयोग करके, आप किसी भी कोर क्लास के मेथड को ओवरराइड कर सकते हैं और अपनी ज़रूरत के मुताबिक इसे ज़ूम कर सकते हैं। लेकिन हम किसी दूसरे दिन के लिए इसे रख देते हैं, क्योंकि एक लेख में फिट होने के लिए बहुत ज्यादा होगा!
तो इस तरह यह सब एक साथ काम करते हैं। मुझे आशा है कि आप उन shorthand OpenCart कॉल्स और उनके आंतरिक कामकाज के बारे में अधिक आश्वस्त हो गए होंगे।
निष्कर्ष
आज हमने जो चर्चा की है, वह OpenCart में दिलचस्प और अस्पष्ट अवधारणाओं (ambiguous) में से एक है: modal के मेथड्स को call करने के लिए शॉर्टहैंड conventions का सपोर्ट से फ्रेमवर्क के Proxy मेथड का प्रयोग। मुझे आशा है कि लेख काफी दिलचस्प था और आपके OprnCart फ्रेमवर्क के ज्ञान को इसने समृद्ध किया।
मुझे इस पर आपकी प्रतिक्रिया जानना अच्छा लगेगा, और अगर आपको लगता है कि मुझे अपने आने वाले लेखों में ऐसे विषयों को कवर करना चाहिए, तो इसके बारे में एक पंक्ति ड्रॉप करने में संकोच न करें!
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post