विभिन्न चर्चाओं और उत्तरों का अवलोकन करने का प्रयास:
इस सवाल का एक भी जवाब नहीं है जो सभी तरीकों issetका इस्तेमाल कर सकता है। कुछ उपयोग के मामलों को अन्य कार्यों द्वारा संबोधित किया जाता है, जबकि अन्य जांच के लिए खड़े नहीं होते हैं, या कोड गोल्फ से परे संदिग्ध मूल्य है। "टूटा हुआ" या "असंगत" होने से दूर, अन्य उपयोग के मामलों में प्रदर्शित issetहोता nullहै कि तार्किक व्यवहार क्यों है।
वास्तविक उपयोग के मामले (समाधान के साथ)
1. सरणी कुंजी
सरणियों के साथ चर के संग्रह की तरह व्यवहार किया जा सकता है, unsetऔर issetउन्हें इलाज के रूप में यद्यपि वे थे। हालाँकि, चूंकि वे इसकी गणना, गणना आदि कर सकते हैं, इसलिए एक लापता मूल्य वह नहीं है जिसका मूल्य है null।
इस मामले में जवाब, के बजाय का उपयोग array_key_exists()करना हैisset() ।
चूँकि यह फ़ंक्शन तर्क के रूप में जांचने के लिए सरणी लेता है, अगर सरणी स्वयं मौजूद नहीं है, तो PHP अभी भी "नोटिस" उठाएगी। कुछ मामलों में, यह वैध रूप से तर्क दिया जा सकता है कि प्रत्येक आयाम को पहले शुरू किया जाना चाहिए था, इसलिए नोटिस अपना काम कर रहा है। अन्य मामलों के लिए, एक "पुनरावर्ती" array_key_existsफ़ंक्शन, जिसने बदले में सरणी के प्रत्येक आयाम की जांच की, इससे बचा जाएगा, लेकिन मूल रूप से एक ही होगा @array_key_exists। यह nullमूल्यों के संचालन के लिए कुछ हद तक स्पर्शरेखा भी है ।
2. वस्तु गुण
"ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग" के पारंपरिक सिद्धांत में, एन्कैप्सुलेशन और बहुरूपता वस्तुओं के प्रमुख गुण हैं; PHP के तरह एक वर्ग आधारित OOP कार्यान्वयन में, समझाया गुण वर्ग परिभाषा के भाग के रूप में घोषित किया जाता है, और यह देखते हुए पहुंच स्तर ( public, protected, या private)।
हालाँकि, PHP आपको गतिशील रूप से किसी ऑब्जेक्ट में गुण जोड़ने की भी अनुमति देता है, जैसे कि आप किसी सरणी में कुंजी डालेंगे, और कुछ लोग क्लास-कम ऑब्जेक्ट्स (तकनीकी रूप से, ऐसे अंतर्निहित इंस्टेंस) का उपयोग करते हैं stdClass, जिनके समान तरीके से कोई विधि या निजी कार्यक्षमता नहीं है) सहयोगी सरणियों के लिए रास्ता। यह उन स्थितियों की ओर जाता है जहां कोई फ़ंक्शन यह जानना चाहता है कि क्या किसी विशेष संपत्ति को दी गई वस्तु में जोड़ा गया है।
सरणी कुंजियों के साथ, ऑब्जेक्ट गुणों की जाँच के लिए एक समाधान भाषा में शामिल है, जिसे उचित रूप से पर्याप्त कहा जाता हैproperty_exists ।
चर्चा के साथ गैर-न्यायसंगत उपयोग के मामले
3. register_globals, और वैश्विक नामस्थान के अन्य प्रदूषण
इस register_globalsसुविधा ने वैरिएबल स्कोप में वैरिएबल जोड़े हैं जिनके नाम HTTP रिक्वेस्ट के पहलुओं (GET और POST पैरामीटर्स और कुकीज) द्वारा निर्धारित किए गए थे। यह छोटी गाड़ी और असुरक्षित कोड को जन्म दे सकता है, यही कारण है कि इसे PHP 4.2 के बाद से डिफ़ॉल्ट रूप से अक्षम कर दिया गया है , अगस्त 2000 को जारी किया गया और पूरी तरह से PHP 5.4 में जारी किया गया, मार्च 2012 को जारी किया गया । हालाँकि, यह संभव है कि कुछ सिस्टम अभी भी इस सुविधा के साथ चल रहे हैं या सक्षम हैं। globalकीवर्ड या $GLOBALSसरणी का उपयोग करके अन्य तरीकों से वैश्विक नामस्थान को "प्रदूषित" करना भी संभव है ।
सबसे पहले, register_globalsस्वयं अप्रत्याशित रूप से एक nullचर का उत्पादन करने की संभावना नहीं है , क्योंकि GET, POST और कुकी मान हमेशा स्ट्रिंग्स होंगे ( ''अभी भी साथ लौट रहे trueहैं isset), और सत्र में चर पूरी तरह से प्रोग्रामर के नियंत्रण में होना चाहिए।
दूसरे, मूल्य के साथ एक चर का प्रदूषण nullकेवल एक मुद्दा है अगर यह पिछले कुछ प्रारंभिक लिखता है। "ओवर राइटिंग" के साथ एक अनइंस्टाल्यूटेड वैरिएबल nullकेवल समस्याग्रस्त होगा यदि कोड कहीं और दो राज्यों के बीच भेद कर रहा था, इसलिए अपने आप ही यह संभावना इस तरह के अंतर को बनाने के खिलाफ एक तर्क है ।
4. get_defined_varsऔरcompact
PHP में कुछ शायद ही कभी उपयोग किए जाने वाले फ़ंक्शन, जैसे get_defined_varsऔर compact, आपको चर नामों का इलाज करने की अनुमति देते हैं जैसे कि वे एक सरणी में चाबियाँ थे। वैश्विक चर के लिए, सुपर-वैश्विक सरणी$GLOBALS समान पहुंच की अनुमति देती है, और अधिक सामान्य है। यदि कोई वैरिएबल संबंधित दायरे में परिभाषित नहीं किया गया है, तो एक्सेस के ये तरीके अलग तरह से व्यवहार करेंगे।
एक बार जब आप इन तंत्रों में से एक का उपयोग करके एक सरणी के रूप में चर के एक सेट का इलाज करने का निर्णय लेते हैं, तो आप उस पर सभी समान संचालन कर सकते हैं जैसे कि सामान्य सरणी पर। फलस्वरूप, देखें १।
कार्यात्मकता जो केवल यह अनुमान लगाने के लिए मौजूद है कि ये कार्य कैसे व्यवहार करने वाले हैं (उदाहरण के लिए "" लौटे हुए सरणी में एक महत्वपूर्ण 'फू' होगा get_defined_vars? ") अतिशयोक्तिपूर्ण है, क्योंकि आप केवल फ़ंक्शन चला सकते हैं और बिना किसी प्रभाव के पता लगा सकते हैं।
4 ए। चर चर ( $$foo)
यद्यपि वे कार्य समान नहीं हैं जो चर के एक समूह को एक साहचर्य सारणी में बदल देते हैं, अधिकांश मामले "चर चर" ("इस दूसरे चर पर आधारित चर को निर्दिष्ट करते हैं") का उपयोग कर सकते हैं और बदले में साहचर्य सरणी का उपयोग किया जा सकता है। ।
एक चर नाम, मौलिक रूप से, प्रोग्रामर द्वारा एक मान को दिया गया लेबल है; यदि आप इसे रन-टाइम पर निर्धारित कर रहे हैं, तो यह वास्तव में एक लेबल नहीं है, लेकिन कुछ कुंजी-मूल्य स्टोर में एक कुंजी है। अधिक व्यावहारिक रूप से, एक सरणी का उपयोग नहीं करने से, आप गणना, पुनरावृति, आदि की क्षमता खो रहे हैं; की-वैल्यू स्टोर के बाहर "वैरिएबल" होना भी असंभव हो सकता है, क्योंकि यह ओवर-राइट हो सकता है $$foo।
एक साहचर्य सरणी का उपयोग करने के लिए बदल जाने के बाद, कोड 1 समाधान के लिए उत्तरदायी होगा $foo->$property_name। समाधान 2 के लिए अप्रत्यक्ष वस्तु संपत्ति पहुंच (जैसे ) को संबोधित किया जा सकता है।
5. issetटाइप करने के लिए इतना आसान हैarray_key_exists
मुझे यकीन नहीं है कि यह वास्तव में प्रासंगिक है, लेकिन हां, PHP के फ़ंक्शन नाम कभी-कभी बहुत लंबे-घुमावदार और असंगत हो सकते हैं। जाहिर तौर पर, PHP के पूर्व-ऐतिहासिक संस्करणों ने एक हैश की के रूप में एक फ़ंक्शन नाम की लंबाई का उपयोग किया था, इसलिए रासमस ने जानबूझकर फ़ंक्शन नाम बनाए जैसे htmlspecialcharsकि उनके पास असामान्य संख्या में वर्ण होंगे ...
फिर भी, कम से कम हम जावा, एह नहीं लिख रहे हैं? ;)
6. Uninitialized चर में एक प्रकार होता है
चर मूल बातें पर मैन्युअल पृष्ठ इस बयान में शामिल हैं:
Uninitialized चर का उपयोग उस संदर्भ के आधार पर उनके प्रकार का डिफ़ॉल्ट मान होता है जिसमें वे उपयोग किए जाते हैं
मुझे यकीन नहीं है कि "अनइंस्टाल्यूटेड लेकिन ज्ञात प्रकार" के ज़ेंड इंजन में कुछ धारणा है या नहीं और यह कथन में बहुत अधिक पढ़ रहा है।
जो स्पष्ट है वह यह है कि यह उनके व्यवहार पर कोई व्यावहारिक अंतर नहीं डालता है, क्योंकि बिन पृष्ठ के लिए उस पृष्ठ पर वर्णित व्यवहार एक चर के व्यवहार के समान हैं, जिसका मूल्य है null। एक उदाहरण लेने के लिए, दोनों $aऔर $bइस कोड में पूर्णांक के रूप में खत्म हो जाएगा 42:
unset($a);
$a += 42;
$b = null;
$b += 42;
(पहले आप एक अघोषित चर के बारे में एक नोटिस उठाएंगे, आपको बेहतर कोड लिखने के प्रयास में, लेकिन इससे कोई फर्क नहीं पड़ेगा कि कोड वास्तव में कैसे चलता है।)
99. यदि कोई फ़ंक्शन चला है, तो पता लगाना
(इसे एक अंतिम रखते हुए, क्योंकि यह दूसरों की तुलना में बहुत लंबा है। शायद मैं इसे बाद में संपादित करूंगा ...)
निम्नलिखित कोड पर विचार करें:
$test_value = 'hello';
foreach ( $list_of_things as $thing ) {
if ( some_test($thing, $test_value) ) {
$result = some_function($thing);
}
}
if ( isset($result) ) {
echo 'The test passed at least once!';
}
अगर some_functionवापस लौट सकते हैं null, तो एक संभावना है कि वापस लौटते हुए echoभी नहीं पहुंच पाएंगे । प्रोग्रामर का इरादा तब पता लगाना था जब कभी सेट नहीं किया गया था, लेकिन पीएचपी उन्हें ऐसा करने की अनुमति नहीं देता है।some_testtrue$result
हालांकि, इस दृष्टिकोण के साथ अन्य समस्याएं हैं, जो बाहरी लूप जोड़ने पर स्पष्ट हो जाती हैं:
foreach ( $list_of_tests as $test_value ) {
// something's missing here...
foreach ( $list_of_things as $thing ) {
if ( some_test($thing, $test_value) ) {
$result = some_function($thing);
}
}
if ( isset($result) ) {
echo 'The test passed at least once!';
}
}
क्योंकि $resultइसे कभी भी स्पष्ट रूप से शुरू नहीं किया गया है, यह बहुत पहले परीक्षण पास होने पर एक मूल्य पर ले जाएगा, जिससे यह बताना असंभव हो जाएगा कि बाद के परीक्षण पास हुए या नहीं। यह वास्तव में एक बहुत ही सामान्य बग है जब चर को ठीक से प्रारंभ नहीं किया जाता है।
इसे ठीक करने के लिए, हमें उस लाइन पर कुछ करने की ज़रूरत है जहाँ मैंने टिप्पणी की है कि कुछ गायब है। सबसे स्पष्ट समाधान $resultएक "टर्मिनल मान" पर सेट करना है जो some_functionकभी वापस नहीं आ सकता है; यदि यह है null, तो बाकी कोड ठीक काम करेगा। यदि टर्मिनल मान के लिए कोई प्राकृतिक उम्मीदवार नहीं है, क्योंकि some_functionएक बेहद अप्रत्याशित रिटर्न प्रकार है (जो संभवतः अपने आप में एक बुरा संकेत है), तो $foundइसके बजाय एक अतिरिक्त बूलियन मूल्य का उपयोग किया जा सकता है।
सोचा प्रयोग एक: very_nullनिरंतर
PHP सैद्धांतिक रूप से एक विशेष स्थिरांक प्रदान कर सकता है - साथ ही null- यहाँ टर्मिनल मान के रूप में उपयोग के लिए; संभवतः, इसे किसी फ़ंक्शन से वापस करना अवैध होगा, या इसे इसके लिए बाध्य किया जाएगा null, और संभवतः इसे फ़ंक्शन तर्क के रूप में पारित करने के लिए लागू होगा। यह इस विशिष्ट मामले को थोड़ा सरल बना देगा, लेकिन जैसे ही आपने कोड को फिर से फैक्टर करने का फैसला किया - उदाहरण के लिए, आंतरिक लूप को एक अलग फ़ंक्शन में डालने के लिए - यह बेकार हो जाएगा। यदि फ़ंक्शंस के बीच निरंतर पारित किया जा सकता है, तो आप गारंटी नहीं दे सकते कि some_functionइसे वापस नहीं किया जाएगा, इसलिए यह अब सार्वभौमिक टर्मिनल मान के रूप में उपयोगी नहीं होगा।
इस मामले में असंवैधानिक चर का पता लगाने के लिए तर्क उस विशेष स्थिरांक के तर्क को उबलता है: यदि आप टिप्पणी को प्रतिस्थापित करते हैं unset($result), और उस से अलग तरीके से व्यवहार $result = nullकरते हैं, तो आप उसके लिए एक "मूल्य" पेश कर रहे हैं, $resultजिसे पास नहीं किया जा सकता, और केवल विशिष्ट अंतर्निहित कार्यों द्वारा पता लगाया गया।
सोचा प्रयोग दो: असाइनमेंट काउंटर
अंतिम क्या ifपूछ रहा है , इस बारे में सोचने का एक और तरीका है "क्या कुछ भी करने के लिए एक असाइनमेंट किया गया है $result?" इसके एक विशेष मूल्य पर विचार करने के बजाय $result, आप शायद चर के बारे में "मेटाडेटा" के रूप में सोच सकते हैं , थोड़ा पर्ल के "वैरिएबल टैनिंग" की तरह। तो बजाय issetआप इसे कॉल कर सकते हैं has_been_assigned_to, और के बजाय unset, reset_assignment_state।
लेकिन अगर ऐसा है, तो एक बूलियन पर क्यों रोकें? क्या होगा यदि आप जानना चाहते हैं कि परीक्षण कितनी बार पारित हुआ; आप बस अपने मेटाडेटा को एक पूर्णांक तक बढ़ा सकते हैं और है get_assignment_countऔर reset_assignment_count...
जाहिर है, इस तरह की सुविधा को जोड़ने से भाषा की जटिलता और प्रदर्शन में एक व्यापार बंद हो जाएगा, इसलिए इसकी अपेक्षित उपयोगिता के खिलाफ सावधानीपूर्वक तौलना होगा। एक very_nullस्थिरांक के रूप में, यह केवल बहुत ही संकीर्ण परिस्थितियों में उपयोगी होगा, और पुन: फैक्टरिंग के समान प्रतिरोधी होगा।
उम्मीद है कि स्पष्ट सवाल यह है कि PHP रनटाइम इंजन को अग्रिम में यह मान लेना चाहिए कि आप सामान्य कोड का उपयोग करके, स्पष्ट रूप से ऐसा करने के लिए छोड़ने के बजाय ऐसी चीजों पर नज़र रखना चाहते हैं।