संदर्भ: चर गुंजाइश क्या है, कौन से चर कहाँ से सुलभ हैं और "अपरिभाषित चर" त्रुटियां क्या हैं?


167

नोट: यह PHP में परिवर्तनशील क्षेत्र से निपटने के लिए एक संदर्भ प्रश्न है। कृपया इस प्रति के रूप में इस पैटर्न को फिट करने वाले कई प्रश्नों को बंद करें।

PHP में "वैरिएबल स्कोप" क्या है? क्या एक .php फ़ाइल से दूसरे में चर उपलब्ध हैं? मुझे कभी-कभी "अपरिभाषित चर" त्रुटियां क्यों मिलती हैं?


1
यदि आप इसे "अपरिभाषित चर" के रूप में शीर्षक देते हैं, तो आपको अधिक हिट मिलेंगे :) अच्छी नौकरी हालांकि
डेल

@ डेल, वास्तव में नहीं। 2 साल में 2k विचार है ....
Pacerier

7
@Pacerier ... एक यादृच्छिक टिप्पणी छोड़ने के लिए सही समय के बारे में?
डेल

@ स्पेसर मुझे वास्तव में यकीन नहीं है कि आप उस टिप्पणी के साथ क्या कहना चाह रहे हैं। "है ...." ... क्या ?! : पी
छल

@ डेल, अब सही समय है: वाह, भले ही 2 साल के लिए सवाल स्थिर हो गया हो, " स्टेटलेस " शब्द को GoogleDex में जोड़ने के बाद , इसकी हिट दर का शाब्दिक अर्थ है केवल 6 महीनों में 3x-ed।
पचेरियर

जवाबों:


188

"वैरिएबल स्कोप" क्या है?

चर के पास एक सीमित "गुंजाइश" है, या "वे स्थान जहां से वे सुलभ हैं"। सिर्फ इसलिए कि आपने $foo = 'bar';एक बार अपने आवेदन में कहीं लिखा है इसका मतलब यह नहीं है कि आप आवेदन के अंदर हर जगह$foo से संदर्भित कर सकते हैं । चर का एक निश्चित दायरा होता है जिसके भीतर यह मान्य होता है और उसी दायरे में केवल कोड ही चर तक पहुंच पाता है।$foo

PHP में एक स्कोप कैसे परिभाषित किया जाता है?

बहुत सरल: PHP में फंक्शन स्कोप है । यह एकमात्र प्रकार का स्कोप विभाजक है जो PHP में मौजूद है। किसी फ़ंक्शन के अंदर चर केवल उस फ़ंक्शन के अंदर उपलब्ध होते हैं। फ़ंक्शंस के बाहर वेरिएबल्स फ़ंक्शंस के बाहर कहीं भी उपलब्ध हैं, लेकिन किसी फ़ंक्शन के अंदर नहीं। इसका मतलब है कि PHP में एक विशेष गुंजाइश है: वैश्विक गुंजाइश। किसी भी फ़ंक्शन के बाहर घोषित किया गया कोई भी वैरिएबल इस वैश्विक दायरे में है।

उदाहरण:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$fooमें है वैश्विक , गुंजाइश $bazएक में है स्थानीय गुंजाइश अंदर myFunc। केवल कोड के अंदर myFuncपहुंच है $baz। केवल बाहर के कोड myFuncतक ही पहुँच है $foo। न ही दूसरे तक पहुंच है:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;

    echo $foo;  // doesn't work
    echo $baz;  // works
}

echo $foo;  // works
echo $baz;  // doesn't work

स्कोप और शामिल फ़ाइलें

फ़ाइल की सीमाएँ अलग-अलग नहीं हैं :

a.php

<?php

$foo = 'bar';

b.php

<?php

include 'a.php';

echo $foo;  // works!

includeडी कोड पर समान नियम लागू होते हैं जैसा कि किसी अन्य कोड पर लागू होता है: केवल functionअलग स्कोप। स्कोप के उद्देश्य के लिए, आप कॉपी और पेस्ट कोड जैसी फ़ाइलों को शामिल करने के बारे में सोच सकते हैं:

c.php

<?php

function myFunc() {
    include 'a.php';

    echo $foo;  // works
}

myFunc();

echo $foo;  // doesn't work!

उपरोक्त उदाहरण में, a.phpअंदर शामिल किया गया था myFunc, a.phpकेवल अंदर के किसी भी चर में स्थानीय फ़ंक्शन गुंजाइश है। सिर्फ इसलिए कि वे दिखाई देते हैं वैश्विक क्षेत्र में होने के लिए a.phpजरूरी नहीं वे कर रहे हैं, यह वास्तव में जो संदर्भ है कि कोड शामिल किया गया है / में मार डाला पर निर्भर करता है।

कार्यों और कक्षाओं के अंदर के कार्यों के बारे में क्या?

हर नई functionघोषणा एक नए दायरे का परिचय देती है, यह इतना आसान है।

(अनाम) कार्यों के अंदर कार्य करता है

function foo() {
    $foo = 'bar';

    $bar = function () {
        // no access to $foo
        $baz = 'baz';
    };

    // no access to $baz
}

कक्षाएं

$foo = 'foo';

class Bar {

    public function baz() {
        // no access to $foo
        $baz = 'baz';
    }

}

// no access to $baz

स्कोप किसके लिए अच्छा है?

टेढ़े मुद्दों से निपटना कष्टप्रद लग सकता है, लेकिन जटिल अनुप्रयोगों को लिखने के लिए सीमित चर गुंजाइश आवश्यक है! यदि आपके द्वारा घोषित किया गया प्रत्येक चर आपके आवेदन के अंदर हर जगह से उपलब्ध होगा, तो आप अपने चर को बिना किसी वास्तविक तरीके के ट्रैक करने के लिए कदम रख सकते हैं कि क्या परिवर्तन होता है। केवल इतने सारे समझदार नाम हैं जो आप अपने चर को दे सकते हैं, आप शायद $nameएक से अधिक स्थानों पर " " चर का उपयोग करना चाहते हैं । यदि आपके ऐप में केवल एक बार ही यह विशिष्ट चर नाम हो सकता है, तो आपको यह सुनिश्चित करने के लिए वास्तव में जटिल नामकरण योजनाओं का सहारा लेना होगा ताकि यह सुनिश्चित हो सके कि आपके चर अद्वितीय हैं और आप गलत चर को गलत कोड से नहीं बदल रहे हैं।

का निरीक्षण करें:

function foo() {
    echo $bar;
}

यदि कोई गुंजाइश नहीं थी, तो उपरोक्त कार्य क्या करेगा? कहाँ $barसे आता है? यह किस राज्य में है? क्या यह भी प्रारंभिक है? क्या आपको हर बार जांच करनी है? यह बनाए रखने योग्य नहीं है। जो हमें लाता है ...

पार की सीमाएँ

सही तरीका: अंदर और बाहर चर चर

function foo($bar) {
    echo $bar;
    return 42;
}

चर $barस्पष्ट रूप से फ़ंक्शन तर्क के रूप में इस दायरे में आ रहा है। इस फ़ंक्शन को देखते हुए यह स्पष्ट है कि मूल्यों की उत्पत्ति कहां से होती है। यह तब स्पष्ट रूप से एक मूल्य देता है। कॉलर को यह जानने का आत्मविश्वास है कि फ़ंक्शन किस चर के साथ काम करेगा और इसके रिटर्न मान कहाँ से आते हैं:

$baz   = 'baz';
$blarg = foo($baz);

अनाम कार्यों में चर के दायरे का विस्तार

$foo = 'bar';

$baz = function () use ($foo) {
    echo $foo;
};

$baz();

अनाम फ़ंक्शन स्पष्ट रूप $fooसे इसके आसपास के दायरे से शामिल है। ध्यान दें कि यह वैश्विक के समान नहीं है दायरे ।

गलत रास्ता: global

जैसा कि पहले कहा गया है, वैश्विक दायरा कुछ विशेष है, और फ़ंक्शन स्पष्ट रूप से इससे चर आयात कर सकते हैं:

$foo = 'bar';

function baz() {
    global $foo;
    echo $foo;
    $foo = 'baz';
}

यह फ़ंक्शन वैश्विक चर का उपयोग करता है और संशोधित करता है $fooयह मत करो! (जब तक आप वास्तव में वास्तव में वास्तव में वास्तव में नहीं जानते कि आप क्या कर रहे हैं, और तब भी: नहीं!)

इस फ़ंक्शन के सभी कॉलर देखता है यह है:

baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!

इस बात का कोई संकेत नहीं है कि इस फ़ंक्शन का कोई दुष्प्रभाव है , फिर भी यह करता है। यह बहुत आसानी से एक उलझी हुई गड़बड़ बन जाता है क्योंकि कुछ कार्य संशोधित होते रहते हैं और कुछ वैश्विक स्थिति की आवश्यकता होती है । आप चाहते हैं कि फंक्शन स्टेटलेस हों , केवल उनके इनपुट्स पर काम करें और परिभाषित आउटपुट लौटें, हालाँकि कई बार आप उन्हें कॉल करते हैं।

आपको किसी भी तरह से वैश्विक गुंजाइश का उपयोग करने से बचना चाहिए; निश्चित रूप से आपको वैश्विक दायरे से बाहर चर को "स्थानीय स्तर पर" खींचना नहीं चाहिए।


आपने अभी के लिए गलत तरीकाglobal कहा है , तो कृपया हमें बताएं कि हमें कब उपयोग करना चाहिए global? और कृपया (थोड़ा) समझाएं कि क्या है static..?

@stack का कोई "सही" तरीका नहीं है global। यह हमेशा गलत है। फ़ंक्शन पैरामीटर पास करना सही है। staticमैनुअल में अच्छी तरह से समझाया गया है और गुंजाइश के साथ बहुत कुछ नहीं है। संक्षेप में इसे "स्कोप्ड ग्लोबल वैरिएबल" माना जा सकता है। मैं यहाँ इसके उपयोग पर थोड़ा विस्तार हो रहा हूँ kunststube.net/static
deceze

मेरा सरल विचार यह है कि अगर एक php वैरिएबल वैश्विक स्थिति के लायक है, तो यह एक डेटाबेस में एक कॉलम के योग्य है। हो सकता है कि यह एक ओवरकिल है, लेकिन यह एक मूर्ख-प्रूफ अप्रोच है जो मेरी औसत प्रोग्रामिंग बुद्धि
आर्थर तरासोव

@ आर्थर वहाँ बहुत कुछ अनपैक करने के लिए है ... ಠ_ is यह सबसे निश्चित रूप से एक दृष्टिकोण है जिसे मैं समर्थन करूंगा।
deceze

@deceze wee बिट का एक तर्क जो आज यहाँ हो रहा है stackoverflow.com/q/51409392 - जहाँ ओपी यह उल्लेख करता है कि डुप्लिकेट (यहाँ) के बारे में उल्लेख नहीं किया गया है include_onceऔर संभवतः require_onceइसे भी कहीं जोड़ा जाना चाहिए; बस केह रहा हू। ओपी ने अपने सवाल को फिर से खोलने के लिए मतदान किया। क्या उनकी पोस्ट एक विशेष मामला होगा और इसके बारे में क्या किया जाना चाहिए?
फंक फोर्टी निनेर

10

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

यह 'स्टैटिक वेरिएबल' क्या है?

स्टैटिक वेरिएबल फंक्शन के स्कोप में परिभाषित होने वाले साधारण वैरिएबल से अलग होता है, क्योंकि जब प्रोग्राम एक्जीक्यूशन इस स्कोप को छोड़ता है तो उसकी वैल्यू ढीली नहीं होती। आइए स्थैतिक चर का उपयोग करने के निम्नलिखित उदाहरण पर विचार करें:

function countSheep($num) {
 static $counter = 0;
 $counter += $num;
 echo "$counter sheep jumped over fence";
}

countSheep(1);
countSheep(2);
countSheep(3);

परिणाम:

1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence

यदि हम $counterबिना परिभाषित किए हैं, staticतो हर बार गूँजती हुई वैल्यू $num, फंक्शन में दिए गए पैरामीटर के समान होगी । का उपयोग करते हुए staticअतिरिक्त वैकल्पिक हल के बिना इस सरल काउंटर का निर्माण करने की अनुमति देता है।

स्थैतिक चर उपयोग-मामलों

  1. कार्य करने के लिए परिणामी कॉल के बीच मूल्यों को संग्रहीत करने के लिए।
  2. पुनरावर्ती कॉलों के बीच मूल्यों को संग्रहीत करने के लिए जब कोई रास्ता नहीं है (या कोई उद्देश्य नहीं) उन्हें पारित करने के रूप में।
  3. मूल्य को कैश करने के लिए जो एक बार पुनः प्राप्त करना बेहतर होता है। उदाहरण के लिए, सर्वर पर अपरिवर्तनीय फ़ाइल पढ़ने का परिणाम।

ट्रिक्स

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

स्टेटिक वेरिएबल को केवल स्केलर के रूप में या स्केलर एक्सप्रेशन के रूप में परिभाषित किया जा सकता है (PHP 5.6 के बाद से)। अन्य मूल्यों को इसे अनिवार्य रूप से सौंपने से कम से कम इस समय इस लेख को लिखा गया था। फिर भी आप अपने कोड की अगली पंक्ति में ऐसा करने में सक्षम हैं:

function countSheep($num) {
  static $counter = 0;
  $counter += sqrt($num);//imagine we need to take root of our sheep each time
  echo "$counter sheep jumped over fence";
}

परिणाम:

2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence

एक ही वर्ग की वस्तुओं के तरीकों के बीच स्थैतिक कार्य थोड़े 'साझा' होते हैं। निम्नलिखित उदाहरण देखकर समझना आसान है:

class SomeClass {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

$object1 = new SomeClass;
$object2 = new SomeClass;

$object1->foo(); // 1
$object2->foo(); // 2 oops, $object2 uses the same static $x as $object1
$object1->foo(); // 3 now $object1 increments $x
$object2->foo(); // 4 and now his twin brother

यह केवल एक ही वर्ग की वस्तुओं के साथ काम करता है। यदि वस्तुएं विभिन्न वर्गों से हैं (यहां तक ​​कि एक दूसरे को विस्तारित करते हुए) स्थैतिक संस्करण का व्यवहार अपेक्षा के अनुरूप होगा।

किसी फ़ंक्शन को कॉल के बीच मान रखने के लिए स्थिर चर एकमात्र तरीका है?

फ़ंक्शन कॉल के बीच मान रखने का दूसरा तरीका क्लोजर का उपयोग करना है। PHP 5.3 में क्लोज़र पेश किए गए थे। दो शब्दों में वे आपको एक फ़ंक्शन स्कोप के भीतर चर के कुछ सेट तक किसी अन्य अनाम फ़ंक्शन तक सीमित करने की अनुमति देते हैं जो उन्हें एक्सेस करने का एकमात्र तरीका होगा। क्लोजर वेरिएबल्स में होने के कारण संरचित प्रोग्रामिंग में 'क्लास कॉन्स्टेंट्स' (यदि वे मूल्य से क्लोजर में पास किए गए) या 'प्राइवेट प्रॉपर्टीज' (यदि संदर्भ द्वारा पास किए जाते हैं) की तरह OOP कॉन्सेप्ट्स (अधिक या कम सफलतापूर्वक) हो सकते हैं।

उत्तरार्द्ध वास्तव में स्थिर चर के बजाय क्लोजर का उपयोग करने की अनुमति देता है। फैसला करने के लिए डेवलपर को क्या उपयोग करना है लेकिन यह उल्लेख किया जाना चाहिए कि रिकर्स के साथ काम करते समय स्थिर चर निश्चित रूप से उपयोगी होते हैं और देवों द्वारा देखे जाने के लायक होते हैं।


2

मैं इस सवाल का पूरा जवाब नहीं दूंगा, क्योंकि मौजूदा वाले और PHP मैनुअल इस बारे में बहुत कुछ समझाने का काम करते हैं।

लेकिन एक विषय है कि याद किया गया था का था superglobals , सहित आमतौर पर इस्तेमाल किया $_POST, $_GET, $_SESSION, आदि इन चरों सरणियों है कि एक के बिना किसी भी दायरे में हमेशा उपलब्ध हैं, कर रहे हैं globalघोषणा।

उदाहरण के लिए, यह फ़ंक्शन PHP स्क्रिप्ट चलाने वाले उपयोगकर्ता के नाम को प्रिंट करेगा। चर बिना किसी समस्या के फ़ंक्शन के लिए उपलब्ध है।

<?php
function test() {
    echo $_ENV["user"];
}

"ग्लोबल्स खराब हैं" के सामान्य नियम को आमतौर पर PHP में संशोधित किया जाता है "ग्लोबल्स खराब हैं, लेकिन सुपरग्लोब ठीक हैं," जब तक कोई उनका दुरुपयोग नहीं कर रहा है। (ये सभी चर गलत हैं, इसलिए यदि आप वास्तव में भयानक थे, तो निर्भरता इंजेक्शन से बचने के लिए इनका उपयोग किया जा सकता है।)

ये चर मौजूद होने की गारंटी नहीं हैं; एक व्यवस्थापक variables_orderनिर्देश का उपयोग करके उनमें से कुछ या सभी को अक्षम कर सकता है php.ini, लेकिन यह सामान्य व्यवहार नहीं है।


वर्तमान सुपरग्लोबल्स की एक सूची:

  • $GLOBALS - वर्तमान स्क्रिप्ट में सभी वैश्विक चर
  • $_SERVER - सर्वर और निष्पादन पर्यावरण पर जानकारी
  • $_GET अनुरोध के लिए उपयोग की जाने वाली HTTP विधि की परवाह किए बिना, URL के क्वेरी स्ट्रिंग में मानों को पारित कर दिया गया
  • $_POST- साथ एक HTTP पोस्ट अनुरोध में पारित मान application/x-www-form-urlencodedया multipart/form-dataMIME प्रकार
  • $_FILES- multipart/form-dataMIME प्रकार के साथ HTTP POST अनुरोध में फ़ाइलें पास हुईं
  • $_COOKIE - कुकीज़ वर्तमान अनुरोध के साथ पारित कर दिया
  • $_SESSION - PHP द्वारा आंतरिक रूप से संग्रहीत सत्र चर
  • $_REQUEST- आमतौर पर $_GETऔर का संयोजन $_POST, लेकिन कभी-कभी $_COOKIES। सामग्री request_orderनिर्देश द्वारा निर्धारित की जाती है php.ini
  • $_ENV - वर्तमान स्क्रिप्ट का पर्यावरण चर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.