मूल प्रश्न पूछे जाने के ठीक 2 साल बाद यहां पहुंचना, कुछ बातें हैं जो मैं बताना चाहता हूं। (मुझे कभी बहुत सी बातें इंगित करने के लिए मत कहो)।
उचित हुक
प्लगइन क्लास को तुरंत करने के लिए, उचित हुक का उपयोग किया जाना चाहिए। एक सामान्य नियम नहीं है जिसके लिए यह है, क्योंकि यह इस बात पर निर्भर करता है कि वर्ग क्या करता है।
एक बहुत ही शुरुआती हुक का उपयोग करना जैसे "plugins_loaded"
कोई मतलब नहीं है क्योंकि एक हुक ऐसा है जो व्यवस्थापक, फ़्रेन्ड और AJAX अनुरोधों के लिए निकाल दिया जाता है, लेकिन बहुत बार बाद में हुक बेहतर होता है क्योंकि यह केवल जरूरत पड़ने पर प्लगइन कक्षाओं को तुरंत करने की अनुमति देता है।
उदाहरण के लिए, सामानों के लिए सामान रखने वाली एक कक्षा को तुरंत चालू किया जा सकता है "template_redirect"
।
आम तौर पर यह बहुत कम ही कहा जाता है कि एक वर्ग को तुरंत "wp_loaded"
निकाल दिया जाना चाहिए।
नो गॉड क्लास
पुराने जवाबों में उदाहरण के रूप में उपयोग की जाने वाली सभी कक्षाएं अधिकांश नाम की एक कक्षा का उपयोग करती हैं "Prefix_Example_Plugin"
या "My_Plugin"
... यह इंगित करता है कि शायद प्लगइन के लिए एक मुख्य वर्ग है।
खैर, जब तक कि एक एकल वर्ग (जिस स्थिति में इसे प्लगइन नाम के बाद नाम देना उचित है,) द्वारा एक प्लगइन बनाया जाता है, एक ऐसा वर्ग बनाने के लिए जो पूरे प्लगइन का प्रबंधन करता है (उदाहरण के लिए सभी हुक जोड़ने की जरूरत है या अन्य सभी प्लगइन वर्गों को तत्काल बनाना है। ) एक बुरा अभ्यास माना जा सकता है, एक देव वस्तु के उदाहरण के रूप में ।
ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग कोड में SOLID होना चाहिए, जहां "S" "सिंगल जिम्मेदारी सिद्धांत" के लिए खड़ा हो ।
इसका मतलब है कि हर वर्ग को एक ही काम करना चाहिए। वर्डप्रेस प्लगइन डेवलपमेंट में इसका मतलब है कि डेवलपर्स को मुख्य प्लगइन क्लास को इंस्टेंट करने के लिए सिंगल हुक का उपयोग करने से बचना चाहिए , लेकिन क्लास की जिम्मेदारी के अनुसार अलग-अलग हुक को अलग-अलग क्लास को इंस्टेंट करने के लिए इस्तेमाल किया जाना चाहिए।
कंस्ट्रक्टर में हुक से बचें
इस तर्क को अन्य उत्तरों में यहाँ प्रस्तुत किया गया है, हालाँकि मैं इस अवधारणा पर टिप्पणी करना चाहता हूँ और इस अन्य उत्तर को जोड़ना चाहता हूँ जहाँ इसे इकाई परीक्षण के दायरे में बहुत व्यापक रूप से समझाया गया है।
लगभग 2015: PHP 5.2 लाश के लिए है
14 अगस्त 2014 के बाद से, PHP 5.3 जीवन के अंत तक पहुंच गया । यह निश्चित रूप से मर चुका है। PHP 5.4 सभी 2015 के लिए समर्थित होने जा रहा है, इसका मतलब है कि मैं एक और वर्ष के लिए लिख रहा हूं।
हालाँकि, वर्डप्रेस अभी भी PHP 5.2 का समर्थन करता है, लेकिन किसी को भी उस संस्करण का समर्थन करने वाली कोड की एक पंक्ति नहीं लिखनी चाहिए, खासकर अगर कोड OOP है।
इसके अलग-अलग कारण हैं:
- PHP 5.2 एक लंबे समय से पहले मर चुका है, इसके लिए कोई सुरक्षा सुधार जारी नहीं किए गए हैं, इसका मतलब है कि यह सुरक्षित नहीं है
- PHP 5.3 में PHP, अनाम फ़ंक्शंस और नाम स्थान वाले सहयोगी के लिए बहुत सारी सुविधाएँ जोड़ी गईं
- PHP के नए संस्करण बहुत तेज हैं । PHP मुफ्त है। इसे अपडेट करना मुफ्त है। यदि आप मुफ्त में तेज़, अधिक सुरक्षित उपयोग कर सकते हैं, तो एक धीमे, असुरक्षित संस्करण का उपयोग क्यों करें?
यदि आप PHP 5.4+ कोड का उपयोग नहीं करना चाहते हैं, तो कम से कम 5.3+ का उपयोग करें
उदाहरण
इस बिंदु पर यह पुराने समय की समीक्षा करने का समय है जो मैंने यहां तक कहा था।
एक बार जब हमें 5.2 के बारे में परवाह नहीं करनी है, तो हम नाम स्थान का उपयोग कर सकते हैं और करना चाहिए।
एकल जिम्मेदारी सिद्धांत को बेहतर ढंग से समझाने के लिए, मेरा उदाहरण 3 वर्गों का उपयोग करेगा, एक जो फ्रंटएंड पर कुछ करता है , एक बैकएंड पर और तीसरा दोनों मामलों में उपयोग किया जाता है।
व्यवस्थापक वर्ग:
namespace GM\WPSE\Example;
class AdminStuff {
private $tools;
function __construct( ToolsInterface $tools ) {
$this->tools = $tools;
}
function setup() {
// setup class, maybe add hooks
}
}
सीमावर्ती वर्ग:
namespace GM\WPSE\Example;
class FrontStuff {
private $tools;
function __construct( ToolsInterface $tools ) {
$this->tools = $tools;
}
function setup() {
// setup class, maybe add hooks
}
}
उपकरण इंटरफ़ेस:
namespace GM\WPSE\Example;
interface ToolsInterface {
function doSomething();
}
और एक उपकरण वर्ग, अन्य दो द्वारा उपयोग किया जाता है:
namespace GM\WPSE\Example;
class Tools implements ToolsInterface {
function doSomething() {
return 'done';
}
}
इस कक्षाएं होने के बाद, मैं उचित हुक का उपयोग करके उन्हें इंस्टेंट कर सकता हूं। कुछ इस तरह:
require_once plugin_dir_path( __FILE__ ) . 'src/ToolsInterface.php';
require_once plugin_dir_path( __FILE__ ) . 'src/Tools.php';
add_action( 'admin_init', function() {
require_once plugin_dir_path( __FILE__ ) . 'src/AdminStuff.php';
$tools = new GM\WPSE\Example\Tools;
global $admin_stuff; // this is not ideal, reason is explained below
$admin_stuff = new GM\WPSE\Example\AdminStuff( $tools );
} );
add_action( 'template_redirect', function() {
require_once plugin_dir_path( __FILE__ ) . 'src/FrontStuff.php';
$tools = new GM\WPSE\Example\Tools;
global $front_stuff; // this is not ideal, reason is explained below
$front_stuff = new GM\WPSE\Example\FrontStuff( $tools );
} );
निर्भरता उलटा और निर्भरता इंजेक्शन
ऊपर दिए गए उदाहरण में मैंने अलग-अलग हुक में अलग-अलग वर्गों को तुरंत लिखने के लिए नाम स्थान और अनाम कार्यों का उपयोग किया, जो मैंने ऊपर कहा था, अभ्यास में डाल दिया।
ध्यान दें कि कैसे नामस्थान बिना किसी उपसर्ग के नाम वाली कक्षाएं बनाने की अनुमति देते हैं।
मैंने एक और अवधारणा लागू की जिसका परोक्ष रूप से ऊपर उल्लेख किया गया था: डिपेंडेंसी इंजेक्शन , यह एक तरीका है कि डिपेंडेंसी इनवर्जन प्रिंसिपल , "डी" को SOLID के ब्रीफकेस में लागू किया जाए ।
Tools
वर्ग "इंजेक्शन" है अन्य दो वर्गों में जब वे instantiated कर रहे हैं, तो इस तरह से यह जिम्मेदारी अलग करने के लिए संभव है।
इसके अलावा, AdminStuff
और FrontStuff
कक्षाएं यह बताने के लिए कि वे एक वर्ग की जरूरत को लागू करने के लिए टाइप हिंटिंग का उपयोग करती हैं ToolsInterface
।
इस तरह से स्वयं या हमारे कोड का उपयोग करने वाले उपयोगकर्ता एक ही इंटरफ़ेस के विभिन्न कार्यान्वयन का उपयोग कर सकते हैं, जिससे हमारा कोड एक ठोस वर्ग के लिए नहीं बल्कि एक अमूर्त के लिए युग्मित हो जाता है: यह वास्तव में डिपेंडेंसी इनवर्जन सिद्धांत के बारे में है।
हालाँकि, ऊपर दिए गए उदाहरण में और सुधार किया जा सकता है। आइए देखें कैसे।
autoloader
बेहतर पठनीय ओओपी कोड लिखने का एक अच्छा तरीका अन्य कोड के साथ प्रकार (इंटरफेसेस, क्लासेस) की परिभाषा को मिक्स करना नहीं है , और हर प्रकार की अपनी फ़ाइल में डालना है।
यह नियम PSR-1 कोडिंग मानकों 1 में से एक भी है ।
हालाँकि, ऐसा करने से पहले, एक वर्ग का उपयोग करने में सक्षम होने के लिए उस फ़ाइल की आवश्यकता होती है जिसमें यह होता है।
यह भारी हो सकता है, लेकिन PHP एक कॉलबैक का उपयोग करके एक वर्ग को ऑटो लोड करने के लिए उपयोगिता फ़ंक्शन प्रदान करता है, जो कि उसके नाम के आधार पर एक फ़ाइल लोड करता है।
नेमस्पेस का उपयोग करना बहुत आसान हो जाता है, क्योंकि अब नाम संरचना के साथ फ़ोल्डर संरचना से मेल खाना संभव है।
यह न केवल संभव है, बल्कि यह एक और PSR मानक (या बेहतर 2: PSR-0 अब पदावनत, और PSR-4 ) है।
उस मानकों का पालन करते हुए विभिन्न उपकरणों का उपयोग करना संभव है जो एक कस्टम ऑटोलॉडेर को कोड किए बिना, ऑटोलैड को संभालते हैं।
मेरा कहना है कि वर्डप्रेस कोडिंग मानकों में फाइलों के नामकरण के लिए अलग नियम हैं।
इसलिए वर्डप्रेस कोर के लिए कोड लिखते समय, डेवलपर्स को WP नियमों का पालन करना होता है, लेकिन कस्टम कोड लिखते समय यह एक डेवलपर विकल्प होता है, लेकिन PSR मानक का उपयोग करना पहले से ही लिखित टूल 2 का उपयोग करना आसान होता है ।
ग्लोबल एक्सेस, रजिस्ट्री और सर्विस लोकेटर पैटर्न।
वर्डप्रेस में प्लगइन कक्षाओं को तत्काल करते समय सबसे बड़े मुद्दों में से एक, कोड के विभिन्न हिस्सों से उन्हें कैसे एक्सेस किया जाए।
वर्डप्रेस स्वयं वैश्विक दृष्टिकोण का उपयोग करता है : चर वैश्विक दायरे में सहेजे जाते हैं, जिससे वे हर जगह सुलभ हो जाते हैं। प्रत्येक WP डेवलपर global
अपने करियर में हजारों बार शब्द टाइप करता है ।
यह भी दृष्टिकोण है जिसका मैंने ऊपर उदाहरण के लिए उपयोग किया है, लेकिन यह बुराई है ।
यह उत्तर पहले से ही मुझे समझाने की अनुमति देने के लिए बहुत लंबा है, लेकिन "वैश्विक चर बुराई" के लिए SERP में पहला परिणाम पढ़ना एक अच्छा प्रारंभिक बिंदु है।
लेकिन वैश्विक चर से बचना कैसे संभव है?
भिन्न भिन्न तरीका होता है।
यहाँ कुछ पुराने उत्तर स्थैतिक उदाहरण दृष्टिकोण का उपयोग करते हैं ।
public static function instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new self;
}
return self::$instance;
}
यह आसान और बहुत अच्छा है, लेकिन यह हर उस वर्ग के पैटर्न को लागू करने के लिए मजबूर करता है जिसे हम एक्सेस करना चाहते हैं।
इसके अलावा, कई बार यह दृष्टिकोण देव वर्ग के मुद्दे पर पड़ने के रास्ते पर डालता है, क्योंकि डेवलपर्स इस पद्धति का उपयोग करके एक मुख्य वर्ग को सुलभ बनाते हैं , और फिर अन्य सभी वर्गों तक पहुंचने के लिए इसका उपयोग करते हैं।
मैंने पहले ही बताया कि देव वर्ग कितना बुरा है, इसलिए स्थैतिक उदाहरण दृष्टिकोण एक अच्छा तरीका है जब एक प्लगइन को केवल एक या दो वर्गों को सुलभ बनाने की आवश्यकता होती है।
इसका मतलब यह नहीं है कि इसका उपयोग केवल कुछ ही वर्गों वाले प्लगइन्स के लिए किया जा सकता है, वास्तव में, जब निर्भरता इंजेक्शन सिद्धांत का ठीक से उपयोग किया जाता है, तो विश्व स्तर पर बड़ी संख्या में पहुंच बनाने की आवश्यकता के बिना सुंदर जटिल एप्लिकेशन बनाना संभव है। वस्तुओं की।
हालांकि, कभी-कभी प्लगइन्स को कुछ वर्गों तक पहुंच बनाने की आवश्यकता होती है, और उस स्थिति में स्थिर उदाहरण दृष्टिकोण भारी होता है।
रजिस्ट्री पैटर्न का उपयोग करने के लिए एक और संभावित दृष्टिकोण है ।
यह इसका एक बहुत ही सरल कार्यान्वयन है:
namespace GM\WPSE\Example;
class Registry {
private $storage = array();
function add( $id, $class ) {
$this->storage[$id] = $class;
}
function get( $id ) {
return array_key_exists( $id, $this->storage ) ? $this->storage[$id] : NULL;
}
}
इस कक्षा का उपयोग करके एक आईडी द्वारा रजिस्ट्री ऑब्जेक्ट में वस्तुओं को संग्रहीत करना संभव है, इसलिए एक रजिस्ट्री तक पहुंच होने से सभी वस्तुओं तक पहुंच संभव है। बेशक जब कोई वस्तु पहली बार बनाई जाती है तो उसे रजिस्ट्री में जोड़ा जाना चाहिए।
उदाहरण:
global $registry;
if ( is_null( $registry->get( 'tools' ) ) ) {
$tools = new GM\WPSE\Example\Tools;
$registry->add( 'tools', $tools );
}
if ( is_null( $registry->get( 'front' ) ) ) {
$front_stuff = new GM\WPSE\Example\FrontStuff( $registry->get( 'tools' ) );
$registry->add( 'front', front_stuff );
}
add_action( 'wp', array( $registry->get( 'front' ), 'wp' ) );
उपरोक्त उदाहरण स्पष्ट करता है कि उपयोगी होने के लिए रजिस्ट्री को विश्व स्तर पर सुलभ होना चाहिए। एकमात्र रजिस्ट्री के लिए एक वैश्विक चर बहुत बुरा नहीं है , हालांकि गैर-वैश्विक शुद्धतावादियों के लिए रजिस्ट्री के लिए स्थिर उदाहरण दृष्टिकोण को लागू करना संभव है, या शायद एक स्थिर चर के साथ एक फ़ंक्शन:
function gm_wpse_example_registry() {
static $registry = NULL;
if ( is_null( $registry ) ) {
$registry = new GM\WPSE\Example\Registry;
}
return $registry;
}
पहली बार फ़ंक्शन को यह कहा जाता है कि यह रजिस्ट्री को तुरंत रद्द कर देगा, बाद की कॉल पर यह इसे वापस कर देगा।
विश्व स्तर पर सुलभ बनाने के लिए एक और वर्डप्रेस-विशिष्ट विधि एक फिल्टर से एक वस्तु उदाहरण लौटा रही है। कुछ इस तरह:
$registry = new GM\WPSE\Example\Registry;
add_filter( 'gm_wpse_example_registry', function() use( $registry ) {
return $registry;
} );
उसके बाद हर जगह रजिस्ट्री की जरूरत है:
$registry = apply_filters( 'gm_wpse_example_registry', NULL );
एक और पैटर्न जिसका उपयोग किया जा सकता है वह है सेवा लोकेटर पैटर्न । यह रजिस्ट्री पैटर्न के समान है, लेकिन सर्विस लोकेटरों को निर्भरता इंजेक्शन का उपयोग करके विभिन्न वर्गों में पास किया जाता है।
इस पैटर्न के साथ मुख्य समस्या यह है कि यह कक्षाओं की निर्भरता को छुपाता है जिससे कोड को बनाए रखने और पढ़ने में मुश्किल होती है।
डि कंटेनर
कोई फर्क नहीं पड़ता कि रजिस्ट्री या सेवा लोकेटर का उपयोग विश्व स्तर पर सुलभ बनाने के लिए किया जाता है, वस्तुओं को वहां संग्रहीत किया जाना चाहिए, और संग्रहीत किए जाने से पहले उन्हें तत्काल करने की आवश्यकता है।
जटिल अनुप्रयोगों में, जहां बहुत अधिक कक्षाएं हैं और उनमें से कई में कई निर्भरताएं हैं, तात्कालिक कक्षाओं के लिए बहुत अधिक कोड की आवश्यकता होती है, इसलिए बग की संभावना बढ़ जाती है: कोड जो मौजूद नहीं है उसमें बग नहीं हो सकते।
पिछले वर्षों में कुछ PHP लाइब्रेरीज़ दिखाई दीं जो PHP डेवलपर्स को ऑब्जेक्ट्स के इंस्टेंस को आसानी से इंस्टेंट और स्टोर करने में मदद करती हैं, स्वचालित रूप से उनकी निर्भरता को हल करती हैं।
इस लाइब्रेरी को डिपेंडेंसी इंजेक्शन कंटेनरों के रूप में जाना जाता है क्योंकि वे निर्भरता को हल करने वाली कक्षाओं को इंस्टेंट करने में सक्षम हैं और वस्तुओं को स्टोर करने और जरूरत पड़ने पर उन्हें वापस करने के लिए भी, एक रजिस्ट्री ऑब्जेक्ट के समान कार्य करते हैं।
आमतौर पर, जब डीआई कंटेनरों का उपयोग करते हैं, तो डेवलपर्स को आवेदन के हर वर्ग के लिए निर्भरताएं निर्धारित करनी होती हैं, और फिर कोड में पहली बार एक वर्ग की आवश्यकता होती है जिसे उचित निर्भरता के साथ त्वरित किया जाता है और उसी उदाहरण को बाद के अनुरोधों पर फिर से लौटाया जाता है। ।
कुछ DI कंटेनर कॉन्फ़िगरेशन के बिना स्वचालित रूप से निर्भरता की खोज करने में सक्षम हैं, लेकिन PHP प्रतिबिंब का उपयोग कर रहे हैं ।
कुछ जाने माने DI कंटेनर हैं:
और बहुत सारे।
मैं यह बताना चाहता हूं कि सरल प्लगइन्स के लिए, जिसमें केवल कुछ वर्गों और वर्गों की बहुत अधिक निर्भरता नहीं है, शायद यह DI कंटेनरों का उपयोग करने के लायक नहीं है: स्थिर इंस्टेंस विधि या एक वैश्विक सुलभ रजिस्ट्री अच्छे समाधान हैं, लेकिन जटिल प्लगइन्स के लिए DI कंटेनर का लाभ स्पष्ट हो जाता है।
बेशक, यहां तक कि डीआई कंटेनर ऑब्जेक्ट्स को एप्लिकेशन में उपयोग करने के लिए सुलभ होना पड़ता है और इस उद्देश्य के लिए उपरोक्त तरीकों में से किसी एक का उपयोग करना संभव है, वैश्विक चर, स्थिर उदाहरण चर, फ़िल्टर के माध्यम से वस्तु वापस करना और इसी तरह।
संगीतकार
DI कंटेनर का उपयोग करने का मतलब अक्सर 3 पार्टी कोड का उपयोग करना होता है। आजकल, PHP में, जब हमें एक बाहरी lib (इसलिए केवल DI कंटेनरों का उपयोग करने की आवश्यकता नहीं होती है, लेकिन कोई भी कोड जो एप्लिकेशन का हिस्सा नहीं है), बस इसे डाउनलोड करना और इसे हमारे एप्लिकेशन फ़ोल्डर में रखना एक अच्छा अभ्यास नहीं माना जाता है। भले ही हम कोड के उस अन्य टुकड़े के लेखक हैं।
बाहरी निर्भरता से एक आवेदन कोड को कम करना बेहतर संगठन, बेहतर विश्वसनीयता और कोड की बेहतर पवित्रता का संकेत है ।
संगीतकार , PHP निर्भरता का प्रबंधन करने के लिए PHP समुदाय में डी-फैक्टो मानक है। WP समुदाय में मुख्य धारा से दूर होना , यह एक ऐसा उपकरण है जिसे हर PHP और वर्डप्रेस डेवलपर को कम से कम जानना चाहिए, यदि उपयोग नहीं किया गया है।
यह उत्तर पहले से ही पुस्तक-आकार है जो आगे की चर्चा की अनुमति देता है, और यहां कम्पोजर पर चर्चा करना भी शायद विषय से दूर है, यह केवल पूर्णता के लिए उल्लेख किया गया था।
अधिक जानकारी के लिए संगीतकार साइट पर जाएँ और यह भी इस को पढ़ने देने के लायक है minisite द्वारा क्यूरेट @Rarst ।
1 PSR PHP फ्रेमवर्क इंटरॉप ग्रुप द्वारा जारी PHP मानक नियम हैं
2 संगीतकार (एक पुस्तकालय जिसका इस उत्तर में उल्लेख किया जाएगा) अन्य बातों के अलावा एक ऑटोलैडर उपयोगिता भी है।