PHP में क्लोज़र ... क्या, ठीक है, वे हैं और आपको उनका उपयोग कब करना होगा?


82

तो मैं एक अच्छा, अप टू डेट, ओरिएंटेड फैशन में साथ-साथ प्रोग्रामिंग कर रहा हूं। मैं नियमित रूप से OOP के विभिन्न पहलुओं का उपयोग करता हूं जो PHP लागू करता है, लेकिन मैं सोच रहा हूं कि मुझे क्लोजर का उपयोग करने की आवश्यकता कब हो सकती है। कोई भी विशेषज्ञ वहां से निकल सकता है जो कुछ प्रकाश को बहा सकता है जब यह क्लोजर को लागू करने के लिए उपयोगी होगा?

जवाबों:


82

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

function replace_spaces ($text) {
    $replacement = function ($matches) {
        return str_replace ($matches[1], ' ', ' ').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
}

यह आपको replacementफ़ंक्शन को स्थानीय रूप से अंदर परिभाषित करने देता है replace_spaces(), ताकि यह न हो:
1) वैश्विक नामस्थान
2 को अव्यवस्थित करना ) लोगों को लाइन से तीन साल नीचे करना आश्चर्यचकित करता है कि वैश्विक रूप से परिभाषित एक फ़ंक्शन क्यों है जो केवल एक दूसरे फ़ंक्शन के अंदर उपयोग किया जाता है।

यह चीजों को व्यवस्थित रखता है। ध्यान दें कि फ़ंक्शन का स्वयं का कोई नाम नहीं है, इसे केवल एक संदर्भ के रूप में परिभाषित और असाइन किया गया है $replacement

लेकिन याद रखें, आपको PHP 5.3 के लिए इंतजार करना होगा :)

आप कीवर्ड के उपयोग से बंद होने वाले दायरे के बाहर भी चर का उपयोग कर सकते हैं use। इस उदाहरण पर विचार करें।

// Set a multiplier  
 $multiplier = 3;

// Create a list of numbers  
 $numbers = array(1,2,3,4);

// Use array_walk to iterate  
 // through the list and multiply  
 array_walk($numbers, function($number) use($multiplier){  
 echo $number * $multiplier;  
 }); 

एक उत्कृष्ट विवरण यहां दिया गया है। php lambdas और closures क्या हैं


1
यह एक भयानक व्याख्या है। +1
डेविड जे एडी

4
मुझे समझ में आया कि आप क्लोजर का उपयोग क्यों करेंगे। ज्यादातर लोग वास्तव में समझ नहीं पाते हैं। +1
कैरी केंडल

10
यह अनाम कार्यों का स्पष्टीकरण है, क्लोजर का स्पष्टीकरण नहीं है। अनाम फ़ंक्शंस, जैसा कि आप कहते हैं, जैसे नामित फ़ंक्शंस जैसे वे वैश्विक नहीं हैं। दूसरी ओर, क्लोज़र, लेक्सिकली-स्कॉप्ड फ्री चर ("उपयोग" के साथ घोषित) वाले कार्य हैं; अर्थात। वे अपने द्वारा घोषित किए गए दायरे से मानों को कॉपी और संदर्भ कर सकते हैं, भले ही बाकी सब कुछ कचरा एकत्र किया गया हो।
वॉर्बो

@Warbo यह सच है; उस समय मैं वास्तव में एक अनाम फ़ंक्शन और क्लोजर के बीच के अंतर को कम नहीं कर पाया। क्लोजर वास्तव में केवल एक बार समझ में आता है जब आप अनाम कार्यों को टटोलते हैं, लेकिन आज तक मुझे अभी भी "स्पष्टीकरण" मिल रहा है कि एक क्लोजर क्या है (जैसे मेरा, 7 साल पहले; ;-)) जो इसके स्कोप पहलू की व्याख्या नहीं करता है।
dirtside

इसलिए मैं कह रहा था, जावास्क्रिप्ट की जाँच करें जहाँ क्लोजर का भारी उपयोग किया जाता है - लेकिन ध्यान रखें कि वेरिएबल स्कोप नियम PHP में भिन्न हैं।
रॉल्फ

17

जब आपको भविष्य में एक फ़ंक्शन की आवश्यकता होगी जो एक कार्य करता है जिसे आपने अभी तय किया है।

उदाहरण के लिए, यदि आप एक कॉन्फ़िग फ़ाइल पढ़ते हैं और कोई एक पैरामीटर आपको बताता है कि hash_methodआपके एल्गोरिथ्म के लिए multiplyइसके बजाय square, आप एक क्लोजर बना सकते हैं जिसका उपयोग उस स्थान पर किया जाएगा जहाँ आपको कुछ करने की आवश्यकता है।

क्लोजर में बनाया जा सकता है (उदाहरण के लिए) config_parser(); यह एक फ़ंक्शन बनाता है जिसे do_hash_method()वेरिएबल लोकल config_parser()(कॉन्फिगर फाइल से) का उपयोग करके बुलाया जाता है । जब भी do_hash_method()बुलाया जाता है, तब भी इसका स्थानीय दायरे में चर तक पहुंच होता है, config_parser()हालांकि इसे उस दायरे में नहीं बुलाया जाता है।

एक उम्मीद से अच्छा काल्पनिक उदाहरण:

function config_parser()
{
    // Do some code here
    // $hash_method is in config_parser() local scope
    $hash_method = 'multiply';

    if ($hashing_enabled)
    {
        function do_hash_method($var)
        {
            // $hash_method is from the parent's local scope
            if ($hash_method == 'multiply')
                return $var * $var;
            else
                return $var ^ $var;
        }
    }
}


function hashme($val)
{
    // do_hash_method still knows about $hash_method
    // even though it's not in the local scope anymore
    $val = do_hash_method($val)
}

मैं बस इस उदाहरण को कॉपी पेस्ट नहीं कर सकता और इसे चला सकता हूं। एक उदाहरण है कि मैं बस चला सकते हैं पसंद किया।
किम स्टैक

3
यह उत्तर घटिया है। यह एक व्यर्थ कथन है: "जब आपको भविष्य में एक फ़ंक्शन की आवश्यकता होगी जो एक कार्य करता है जिसे आपने अभी तय किया है।"
साइप्रस में आराम

15

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

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


10

मुझे ट्रॉयल्सन की पोस्ट द्वारा प्रदान किया गया संदर्भ पसंद है। जब मैं PHP में Dan Udey के उदाहरण जैसा कुछ करना चाहता हूं, तो मैं OO रणनीति पैटर्न का उपयोग करता हूं। मेरी राय में, यह एक नए वैश्विक कार्य को शुरू करने से बेहतर है जिसका व्यवहार रनटाइम पर निर्धारित किया गया है।

http://en.wikipedia.org/wiki/Strategy_pattern

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

class ConfigurableEncoder{
        private $algorithm = 'multiply';  //default is multiply

        public function encode($x){
                return call_user_func(array($this,$this->algorithm),$x);
        }

        public function multiply($x){
                return $x * 5;
        }

        public function add($x){
                return $x + 5;
        }

        public function setAlgorithm($algName){
                switch(strtolower($algName)){
                        case 'add':
                                $this->algorithm = 'add';
                                break;
                        case 'multiply':        //fall through
                        default:                //default is multiply
                                $this->algorithm = 'multiply';
                                break;
                }
        }
}

$raw = 5;
$encoder = new ConfigurableEncoder();                           // set to multiply
echo "raw: $raw\n";                                             // 5
echo "multiply: " . $encoder->encode($raw) . "\n";              // 25
$encoder->setAlgorithm('add');
echo "add: " . $encoder->encode($raw) . "\n";                   // 10

बेशक, अगर आप चाहते हैं कि यह हर जगह उपलब्ध हो, तो आप बस सब कुछ स्थिर बना सकते हैं ...


2

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

PHP में, वे "ग्लोबल" (या "बाहरी") चर के दायरे और पहुंच में अंतर के कारण जावास्क्रिप्ट से कम प्रभावी होते हैं, जो कार्यों के भीतर से होते हैं। फिर भी, PHP 5.4 के साथ शुरू होकर, क्लोज़र $ $ इस ऑब्जेक्ट तक पहुँच सकते हैं जब किसी ऑब्जेक्ट के अंदर चलाया जाता है, तो यह उन्हें बहुत अधिक प्रभावी बनाता है।

यह वही है जो बंद होने के बारे में है, और यह समझने के लिए पर्याप्त होना चाहिए कि ऊपर क्या लिखा गया है।

इसका मतलब यह है कि फ़ंक्शन परिभाषा को कहीं पर लिखना संभव है, और फ़ंक्शन परिभाषा के अंदर $ इस चर का उपयोग करें, फिर फ़ंक्शन परिभाषा को एक चर में असाइन करें (दूसरों ने वाक्यविन्यास के उदाहरण दिए हैं), फिर इस चर को किसी ऑब्जेक्ट पर पास करें और इसे ऑब्जेक्ट संदर्भ में कॉल करें, फ़ंक्शन तब $ के माध्यम से ऑब्जेक्ट को एक्सेस और हेरफेर कर सकता है जैसे कि यह सिर्फ एक और एक तरीका है, जब वास्तव में यह उस ऑब्जेक्ट की वर्ग परिभाषा में परिभाषित नहीं होता है, लेकिन कहीं और।

यदि यह बहुत स्पष्ट नहीं है, तो चिंता न करें, एक बार जब आप उनका उपयोग करना शुरू कर देंगे तो यह स्पष्ट हो जाएगा।


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

1

मूल रूप से, क्लोजर आंतरिक कार्य हैं बाहरी बाहरी चर तक पहुंच होती है और कॉलबैक फ़ंक्शन के रूप में इसे एनोनिमस फ़ंक्शन (ऐसे फ़ंक्शन जिनका कोई नाम नहीं है) के रूप में उपयोग किया जाता है।

 <?php
      $param='ironman';
      function sayhello(){
          $param='captain';
          $func=function () use ($param){
                $param='spiderman';
          };
       $func();
       echo  $param;
       }
      sayhello();
?>

//output captain

//and if we pass variable as a reference as(&$param) then output would be spider man;

$param='captain'दुर्गंध sayhello()में स्थानीय चर है sayhello()$param='ironman'ऊपर sayhello()वैश्विक परिवर्तनशील है। आप अपनी स्क्रिप्ट में केवल एक $ परम चर बनाना चाहते हैं आप कॉल करना चाहिए: global $param;भीतर sayhello()समारोह
vlakov

0

यहां php में क्लोजर के उदाहरण दिए गए हैं

// Author: HishamDalal@gamil.com
// Publish on: 2017-08-28

class users
{
    private $users = null;
    private $i = 5;

    function __construct(){
        // Get users from database
        $this->users = array('a', 'b', 'c', 'd', 'e', 'f');
    }

    function displayUsers($callback){
        for($n=0; $n<=$this->i; $n++){
            echo  $callback($this->users[$n], $n);
        }
    }

    function showUsers($callback){
        return $callback($this->users);

    }

    function getUserByID($id, $callback){
        $user = isset($this->users[$id]) ? $this->users[$id] : null;
        return $callback($user);
    }

}

$u = new users();

$u->displayUsers(function($username, $userID){
    echo "$userID -> $username<br>";
});

$u->showUsers(function($users){
    foreach($users as $user){
        echo strtoupper($user).' ';
    }

});

$x = $u->getUserByID(2, function($user){

    return "<h1>$user</h1>";
});

echo ($x);

आउटपुट:

0 -> a
1 -> b
2 -> c
3 -> d
4 -> e
5 -> f

A B C D E F 

c

0

क्लोजर:

MDN का सबसे अच्छा विवरण IMO है:

एक क्लोजर एक फ़ंक्शन के संयोजन (संलग्न) को उसके आसपास के राज्य (लेक्सिकल वातावरण) के संदर्भ में जोड़ा जाता है। दूसरे शब्दों में, एक क्लोजर आपको एक आंतरिक फ़ंक्शन से बाहरी फ़ंक्शन के दायरे तक पहुंच प्रदान करता है।

यानी A क्लोजर एक ऐसा फंक्शन है जिसमें उन वेरिएबल्स तक पहुंच होती है जो पैरेंट स्कोप में होते हैं। एक बंद करने से हमें आसानी से मक्खी पर कार्य करने की अनुमति मिलती है क्योंकि कुछ स्थितियों में केवल एक स्थान (कॉलबैक, कॉल करने योग्य तर्क) में एक फ़ंक्शन की आवश्यकता होती है।

उदाहरण:

$arr = [1,2,3,3];
$outersScopeNr = 2;

// The second arg in array_filter is a closure
// It would be inconvenient to have this function in global namespace
// The use keyword lets us access a variable in an outer scope
$newArr = array_filter($arr, function ($el) use ($outersScopeNr) {
    return $el === 3 || $el === $outersScopeNr;
});

var_dump($newArr);
// array (size=3)
//  1 => int 2
//  2 => int 3
//  3 => int 3
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.