পিএইচপি-তে, একটি বন্ধ কী এবং কেন এটি "ব্যবহার" শনাক্তকারী ব্যবহার করে?


407

আমি কিছু PHP 5.3.0বৈশিষ্ট্য যাচাই করে দেখছি এবং সাইটে বেশ কয়েকটি কোড জুড়ে দৌড়ে গেছে যা বেশ মজার দেখাচ্ছে:

public function getTotal($tax)
{
    $total = 0.00;

    $callback =
        /* This line here: */
        function ($quantity, $product) use ($tax, &$total)
        {
            $pricePerItem = constant(__CLASS__ . "::PRICE_" .
                strtoupper($product));
            $total += ($pricePerItem * $quantity) * ($tax + 1.0);
        };

    array_walk($this->products, $callback);
    return round($total, 2);
}

বেনামী ফাংশনগুলির উদাহরণগুলির মধ্যে একটি হিসাবে ।

কেউ কি এই সম্পর্কে জানেন? কোন ডকুমেন্টেশন? এবং এটি খারাপ দেখাচ্ছে, এটি কখনও ব্যবহার করা উচিত?

উত্তর:


362

পিএইচপি এইভাবে বন্ধের প্রকাশ করে । এটি মোটেও মন্দ নয় এবং বাস্তবে এটি বেশ শক্তিশালী এবং দরকারী।

মূলত এর অর্থ হ'ল আপনি বেনামে ফাংশনটিকে স্থানীয় ভেরিয়েবলগুলি "ক্যাপচার" করার সুযোগ দিচ্ছেন (এই ক্ষেত্রে, $taxএবং একটি রেফারেন্সে $total) এর বাইরে এবং তাদের মানগুলি (বা নিজেই $totalরেফারেন্সের ক্ষেত্রে $total) এর মধ্যে রাষ্ট্র হিসাবে সংরক্ষণ করুন বেনামে ফাংশন নিজেই।


1
সুতরাং এটি কেবল বন্ধের জন্য ব্যবহৃত হয়? আপনাকে ব্যাখ্যার জন্য ধন্যবাদ, আমি বেনামে ফাংশন এবং বন্ধের মধ্যে পার্থক্য জানতাম না
সানডাউনে

136
useশব্দ এছাড়াও জন্য ব্যবহার করা হয় এলিয়াসিং নামব্যবধান । এটি আশ্চর্যজনক যে, পিএইচপি 5.3.0 প্রকাশের 3 বছরেরও বেশি পরে সিনট্যাক্সটি function ... useএখনও আনুষ্ঠানিকভাবে অননুমোদিত, যা ক্লোজারগুলিকে একটি অনিরাপদযুক্ত বৈশিষ্ট্য তৈরি করে। এমনকি ডক এমনকি বেনামে ফাংশন এবং বন্ধগুলি গুলিয়ে দেয়use ()আমি পিএইচপি.এন.টি- তে কেবলমাত্র (বিটা এবং আনঅফিসিয়াল) ডকুমেন্টেশন হ'ল ক্লোজারগুলির জন্য আরএফসি

2
সুতরাং পিএইচপি-তে ফাংশন ব্যবহারের ক্লোজারগুলি কখন কার্যকর করা হয়েছিল? আমার ধারণা তখন এটি পিএইচপি 5.3 এ ছিল? এটি কি এখন কোনওভাবে পিএইচপি ম্যানুয়ালটিতে নথিবদ্ধ হয়?
rubo77

@ মাইটস্কাইন ওয়েল, ডক অনুসারে, বেনামে ফাংশনগুলি ক্লোজার ক্লাস ব্যবহার করে
ম্যানি ফ্লুরমন্ড

1
এখন useএটিকে একটিতে অন্তর্ভুক্ত করার জন্যও ব্যবহৃত traitহয় class!
সিজে ডেনিস

477

একটি সহজ উত্তর।

function ($quantity) use ($tax, &$total) { .. };

  1. ক্লোজারটি একটি চলককে বরাদ্দ করা একটি ফাংশন, যাতে আপনি এটি চারপাশে পাস করতে পারেন
  2. একটি ক্লোজার হল একটি পৃথক নেমস্পেস, সাধারণত, আপনি এই নেমস্পেসের বাইরে সংজ্ঞায়িত ভেরিয়েবলগুলি অ্যাক্সেস করতে পারবেন না। ব্যবহারের কীওয়ার্ডটি এখানে আসে :
  3. ব্যবহার আপনাকে বন্ধের অভ্যন্তরে সফল ভেরিয়েবলগুলি অ্যাক্সেস (ব্যবহার) করতে দেয়।
  4. ব্যবহার তাড়াতাড়ি বাঁধাই। এর অর্থ হল যে পরিবর্তনশীল মানগুলি ক্লোজারটি নির্ধারণের সময় কপি করা হয়। সুতরাং$taxবন্ধের অভ্যন্তরেসংশোধন করারকোনও বাহ্যিক প্রভাব নেই, যদি না এটি কোনও পয়েন্টার হিসাবে থাকে তবে।
  5. ক্ষেত্রে যেমন পয়েন্টার হিসাবে আপনি ভেরিয়েবল পাস করতে পারেন &$total। এইভাবে, $totalবাহ্যিক প্রভাব রাখে মূল ভেরিয়েবলের মান পরিবর্তিত হয় of
  6. বন্ধের ভিতরে সংজ্ঞায়িত চলকগুলি বন্ধের বাইরে থেকে অ্যাক্সেসযোগ্য নয়।
  7. বন্ধ এবং ফাংশনগুলির একই গতি থাকে। হ্যাঁ, আপনি এগুলি আপনার সমস্ত স্ক্রিপ্টে ব্যবহার করতে পারেন।

@Mytskine হিসাবে নির্দিষ্ট সম্ভবত শ্রেষ্ঠ গভীর ব্যাখ্যা বন্ধ জন্য বোঝায় যা RFC । (এর জন্য তাকে উজ্জীবিত করুন))


4
ব্যবহারের বিবৃতিতে শব্দ আমার পিএইচপি 5.5 মধ্যে একটি বাক্য গঠন ত্রুটি দিচ্ছেন: $closure = function ($value) use ($localVar as $alias) { //stuff};ত্রুটি দেওয়া হয়:Parse: syntax error, unexpected 'as' (T_AS), expecting ',' or ')'
কাল Zekdor

1
@ কালজেকডোর, পিএইচপি 5.3 এর সাথে নিশ্চিত হওয়াও অবচিত বলে মনে হচ্ছে। আমি উত্তর আপডেট করেছি, আপনার প্রচেষ্টার জন্য ধন্যবাদ।
জুলু

4
আমি # 5 পয়েন্টে যুক্ত করব যে এইভাবে, পয়েন্টারটির মতো মানটি সংশোধন করার &$totalসাথে সাথে একটি অভ্যন্তরীণ প্রভাবও রয়েছে। অন্য কথায়, আপনি সংজ্ঞায়িত হওয়ার পরে যদি ক্লোজারের $total বাইরের মান পরিবর্তন করেন তবে নতুন মানটি যদি কেবল পয়েন্টার হয় তবে তা পাস হয়ে যায়।
বিলেণোহ

2
@ অ্যানডিডি 73৩৩ উদ্দেশ্যটি globalবিশ্বব্যাপী নেমস্পেসে অ্যাক্সেসের অনুমতি ব্যতীত প্রকৃতপক্ষে খুব অনুরূপ, যেখানে useপ্যারেন্ট নেমস্পেসে ভেরিয়েবল অ্যাক্সেসের অনুমতি দেয়। গ্লোবাল ভেরিয়েবলগুলি সাধারণত মন্দ হিসাবে বিবেচিত হয়। প্যারেন্ট স্কোপ অ্যাক্সেস করা প্রায়শই একটি ক্লোজার তৈরির খুব উদ্দেশ্য। এটি "দুষ্ট" নয় কারণ এর পরিধি খুব সীমিত। জেএস-এর মতো অন্যান্য ভাষাও পিতামহীন স্কোপের ভেরিয়েবলগুলি স্পষ্টভাবে ব্যবহার করে (পয়েন্টার হিসাবে, কপি করা মান হিসাবে নয়)।
zupa

1
এই লাইনটি আমার দুই ঘন্টা নিরর্থক অনুসন্ধান বন্ধ করে দিয়েছেYou can pass in variables as pointers like in case of &$total. This way, modifying the value of $total DOES HAVE an external effect, the original variable's value changes.
ব্ল্যাকপার্ল

69

function () use () {}পিএইচপি জন্য অবসান ভালো হয়।

ছাড়া use, ফাংশন প্যারেন্ট স্কোপ ভেরিয়েবল অ্যাক্সেস করতে পারে না

$s = "hello";
$f = function () {
    echo $s;
};

$f(); // Notice: Undefined variable: s
$s = "hello";
$f = function () use ($s) {
    echo $s;
};

$f(); // hello

useপরিবর্তনশীল এর মান যখন ফাংশন সংজ্ঞায়িত করা হয়, যখন বলা হয় না থেকে

$s = "hello";
$f = function () use ($s) {
    echo $s;
};

$s = "how are you?";
$f(); // hello

use সাথে পরিবর্তনশীল বাই রেফারেন্স &

$s = "hello";
$f = function () use (&$s) {
    echo $s;
};

$s = "how are you?";
$f(); // how are you?

4
এটি পড়ার পরে আমি কিছুটা বেশি স্ক্রোলিংয়ের জন্য অনুশোচনা করছি না তবে তৃতীয় ব্লকে টাইপোর জন্য একটি ছোটখাটো সম্পাদনা প্রয়োজন বলে অনুমান করুন। $ আপজের পরিবর্তে be গুলি থাকা উচিত।
ব্যবহারকারী

53

বন্ধ সুন্দর! তারা বেনামে ফাংশন নিয়ে আসা অনেকগুলি সমস্যা সমাধান করে এবং সত্যই মার্জিত কোডটি সম্ভব করে তোলে (কমপক্ষে যতক্ষণ আমরা পিএইচপি সম্পর্কে কথা বলি)।

জাভাস্ক্রিপ্ট প্রোগ্রামাররা সমস্ত সময় ক্লোজার ব্যবহার করে, কখনও কখনও এটি না জেনেও, কারণ সীমাবদ্ধ ভেরিয়েবলগুলি সুস্পষ্টভাবে সংজ্ঞায়িত হয় না - এটিই পিএইচপি-তে "ব্যবহার" "

উপরের উদাহরণগুলির চেয়ে আরও ভাল বাস্তব-বিশ্বের উদাহরণ রয়েছে। আসুন আপনাকে একটি উপ-মান অনুসারে বহুমাত্রিক অ্যারে বাছাই করতে হবে তবে মূল পরিবর্তনগুলি।

<?php
    function generateComparisonFunctionForKey($key) {
        return function ($left, $right) use ($key) {
            if ($left[$key] == $right[$key])
                return 0;
            else
                return ($left[$key] < $right[$key]) ? -1 : 1;
        };
    }

    $myArray = array(
        array('name' => 'Alex', 'age' => 70),
        array('name' => 'Enrico', 'age' => 25)
    );

    $sortByName = generateComparisonFunctionForKey('name');
    $sortByAge  = generateComparisonFunctionForKey('age');

    usort($myArray, $sortByName);

    usort($myArray, $sortByAge);
?>

সতর্কতা: অরক্ষিত কোড (আমার পিএইচপি 5.3 এটিএম ইনস্টল নেই) তবে এটির মতো দেখতে হবে।

এর একটি খারাপ দিক রয়েছে: আপনি যদি ক্লোজারের সাথে তাদের মুখোমুখি হন তবে অনেকগুলি পিএইচপি বিকাশকারী কিছুটা অসহায় হতে পারেন।

ক্লোজারের চমত্কার বিষয়টিকে আরও বুঝতে, আমি আপনাকে আরও একটি উদাহরণ দেব - এবার জাভাস্ক্রিপ্টে। সমস্যাগুলির মধ্যে একটি হ'ল স্কোপিং এবং ব্রাউজার অন্তর্নিহিত অ্যাসিনক্রোনটি। বিশেষত, যদি এটি window.setTimeout();(বা-অন্তর্বর্তী) আসে । সুতরাং, আপনি সেট টাইমআউটে একটি ফাংশন পাস, কিন্তু আপনি সত্যিই কোনও পরামিতি দিতে পারবেন না, কারণ পরামিতি সরবরাহ করে কোড কার্যকর করে!

function getFunctionTextInASecond(value) {
    return function () {
        document.getElementsByName('body')[0].innerHTML = value; // "value" is the bound variable!
    }
}

var textToDisplay = prompt('text to show in a second', 'foo bar');

// this returns a function that sets the bodys innerHTML to the prompted value
var myFunction = getFunctionTextInASecond(textToDisplay);

window.setTimeout(myFunction, 1000);

মাই ফাংশন এক ধরণের পূর্বনির্ধারিত প্যারামিটার সহ একটি ফাংশন দেয়!

সত্যি কথা বলতে, আমি পিএইচপি 5.3 এবং বেনামে ফাংশন / বন্ধকরণের থেকে অনেক বেশি পছন্দ করি। নেমস্পেসগুলি আরও গুরুত্বপূর্ণ হতে পারে তবে সেগুলি অনেক কম সেক্সি


4
ওহহহহহ, সুতরাং অতিরিক্ত ভেরিয়েবলগুলিতে পাস করার জন্য ব্যবহারগুলি ব্যবহৃত হয় , আমি ভেবেছিলাম এটি কিছু মজার কাজ। ধন্যবাদ!
সানডাউনে

38
সাবধান হও. ফাংশনটি কল করা হলে মানগুলি পাস করার জন্য প্যারামিটারগুলি ব্যবহৃত হয়। ফাংশন সংজ্ঞায়িত হলে ক্লোজারগুলি "পাস" মানগুলিতে ব্যবহৃত হয়।
স্টিফস

জাভাস্ক্রিপ্টে, ব্যবহার করতে পারেন বেঁধে () ফাংশন প্রাথমিক আর্গুমেন্ট উল্লেখ করার - দেখুন আংশিকভাবে প্রয়োগ ফাংশন
সাউ অনোস্ট

17

'ব্যবহার' এবং আর্লিবাইন্ডিং এবং 'ব্যবহৃত' ভেরিয়েবলগুলি উল্লেখ করার মধ্যে পার্থক্য বোঝানোর সাথে জুপা দুর্দান্ত কাজ করেছিলেন a

সুতরাং আমি ভেরিয়েবলের প্রথম বন্ডিংয়ের সাথে একটি কোড উদাহরণ তৈরি করেছি (= অনুলিপি করা):

<?php

$a = 1;
$b = 2;

$closureExampleEarlyBinding = function() use ($a, $b){
    $a++;
    $b++;
    echo "Inside \$closureExampleEarlyBinding() \$a = ".$a."<br />";
    echo "Inside \$closureExampleEarlyBinding() \$b = ".$b."<br />";    
};

echo "Before executing \$closureExampleEarlyBinding() \$a = ".$a."<br />";
echo "Before executing \$closureExampleEarlyBinding() \$b = ".$b."<br />";  

$closureExampleEarlyBinding();

echo "After executing \$closureExampleEarlyBinding() \$a = ".$a."<br />";
echo "After executing \$closureExampleEarlyBinding() \$b = ".$b."<br />";

/* this will output:
Before executing $closureExampleEarlyBinding() $a = 1
Before executing $closureExampleEarlyBinding() $b = 2
Inside $closureExampleEarlyBinding() $a = 2
Inside $closureExampleEarlyBinding() $b = 3
After executing $closureExampleEarlyBinding() $a = 1
After executing $closureExampleEarlyBinding() $b = 2
*/

?>

একটি ভেরিয়েবল উল্লেখ সহ উদাহরণ (ভেরিয়েবলের আগে '&' চরিত্রটি লক্ষ্য করুন);

<?php

$a = 1;
$b = 2;

$closureExampleReferencing = function() use (&$a, &$b){
    $a++;
    $b++;
    echo "Inside \$closureExampleReferencing() \$a = ".$a."<br />";
    echo "Inside \$closureExampleReferencing() \$b = ".$b."<br />"; 
};

echo "Before executing \$closureExampleReferencing() \$a = ".$a."<br />";
echo "Before executing \$closureExampleReferencing() \$b = ".$b."<br />";   

$closureExampleReferencing();

echo "After executing \$closureExampleReferencing() \$a = ".$a."<br />";
echo "After executing \$closureExampleReferencing() \$b = ".$b."<br />";    

/* this will output:
Before executing $closureExampleReferencing() $a = 1
Before executing $closureExampleReferencing() $b = 2
Inside $closureExampleReferencing() $a = 2
Inside $closureExampleReferencing() $b = 3
After executing $closureExampleReferencing() $a = 2
After executing $closureExampleReferencing() $b = 3
*/

?>

2

খুব সাম্প্রতিক বছরগুলি অবধি, পিএইচপি তার এএসটি সংজ্ঞায়িত করেছে এবং পিএইচপি ইন্টারপ্রেটার মূল্যায়ন অংশ থেকে পার্সারকে আলাদা করেছে। ক্লোজারটি চালু হওয়ার সময় পিএইচপি-র পার্সার মূল্যায়নের সাথে অত্যন্ত মিলিত হয়।

সুতরাং ক্লোজারটি প্রথম যখন পিএইচপি-র সাথে পরিচয় করানো হয়েছিল, তখন দোভাষীটির কাছে বন্ধের মধ্যে কোন ভেরিয়েবলগুলি ব্যবহৃত হবে তা জানার কোনও পদ্ধতি নেই কারণ এটি এখনও বিশ্লেষণ করা হয়নি। সুতরাং ব্যবহারকারীকে জেনড ইঞ্জিনকে সুস্পষ্ট আমদানি করে খুশি করতে হবে, জেন্ডের যে হোমওয়ার্ক করা উচিত doing

এটি পিএইচপি-র তথাকথিত সহজ উপায়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.