खोज…
एक बंद का मूल उपयोग
एक क्लोजर PHP एक अनाम फ़ंक्शन के बराबर है, जैसे। एक फ़ंक्शन जिसमें कोई नाम नहीं है। भले ही वह तकनीकी रूप से सही नहीं है, लेकिन कुछ अतिरिक्त सुविधाओं के साथ, एक क्लोजर का व्यवहार फ़ंक्शन के समान रहता है।
एक क्लोजर कुछ भी नहीं है, लेकिन क्लोजर क्लास की एक वस्तु है जो बिना नाम के एक फ़ंक्शन की घोषणा करके बनाई गई है। उदाहरण के लिए:
<?php
$myClosure = function() {
echo 'Hello world!';
};
$myClosure(); // Shows "Hello world!"
ध्यान रखें कि $myClosure
Closure
का एक उदाहरण है ताकि आप इस बात से अवगत हों कि आप वास्तव में इसके साथ क्या कर सकते हैं (cf. http://fr2.php.net/manual/en/class.closure.php )
क्लासिक मामले आप एक बंद की आवश्यकता होगी आप एक देना है जब है callable
उदाहरण के लिए, एक समारोह को usort ।
यहाँ एक उदाहरण है जहाँ एक सरणी को प्रत्येक व्यक्ति के भाई-बहनों की संख्या के आधार पर क्रमबद्ध किया जाता है:
<?php
$data = [
[
'name' => 'John',
'nbrOfSiblings' => 2,
],
[
'name' => 'Stan',
'nbrOfSiblings' => 1,
],
[
'name' => 'Tom',
'nbrOfSiblings' => 3,
]
];
usort($data, function($e1, $e2) {
if ($e1['nbrOfSiblings'] == $e2['nbrOfSiblings']) {
return 0;
}
return $e1['nbrOfSiblings'] < $e2['nbrOfSiblings'] ? -1 : 1;
});
var_dump($data); // Will show Stan first, then John and finally Tom
बाहरी चर का उपयोग करना
यह संभव है, एक बंद के अंदर, विशेष कीवर्ड के उपयोग के साथ एक बाहरी चर का उपयोग करने के लिए । उदाहरण के लिए:
<?php
$quantity = 1;
$calculator = function($number) use($quantity) {
return $number + $quantity;
};
var_dump($calculator(2)); // Shows "3"
आप "गतिशील" क्लोजर बनाकर आगे बढ़ सकते हैं। एक फ़ंक्शन बनाना संभव है जो एक विशिष्ट कैलकुलेटर लौटाता है, जो आप जोड़ना चाहते हैं उस मात्रा पर निर्भर करता है। उदाहरण के लिए:
<?php
function createCalculator($quantity) {
return function($number) use($quantity) {
return $number + $quantity;
};
}
$calculator1 = createCalculator(1);
$calculator2 = createCalculator(2);
var_dump($calculator1(2)); // Shows "3"
var_dump($calculator2(2)); // Shows "4"
बेसिक क्लोजर बाइंडिंग
जैसा कि पहले देखा गया है, क्लोजर क्लास के एक उदाहरण के अलावा एक बंद कुछ भी नहीं है, और उन पर विभिन्न तरीकों को लागू किया जा सकता है। उनमें से एक bindTo
, जिसे एक क्लोजर दिया गया है, एक नया लौटाएगा जो किसी दिए गए ऑब्जेक्ट के लिए बाध्य है। उदाहरण के लिए:
<?php
$myClosure = function() {
echo $this->property;
};
class MyClass
{
public $property;
public function __construct($propertyValue)
{
$this->property = $propertyValue;
}
}
$myInstance = new MyClass('Hello world!');
$myBoundClosure = $myClosure->bindTo($myInstance);
$myBoundClosure(); // Shows "Hello world!"
समापन बंधन और गुंजाइश
आइए इस उदाहरण पर विचार करें:
<?php
$myClosure = function() {
echo $this->property;
};
class MyClass
{
public $property;
public function __construct($propertyValue)
{
$this->property = $propertyValue;
}
}
$myInstance = new MyClass('Hello world!');
$myBoundClosure = $myClosure->bindTo($myInstance);
$myBoundClosure(); // Shows "Hello world!"
property
दृश्यता को protected
या private
बदलने की कोशिश करें। आपको यह इंगित करने में एक घातक त्रुटि मिलती है कि आपके पास इस संपत्ति तक पहुंच नहीं है। वास्तव में, भले ही बंद वस्तु के लिए बाध्य किया गया हो, जिस दायरे को बंद किया जाता है वह उस पहुंच के लिए आवश्यक नहीं है। यह वही है जो bindTo
का दूसरा तर्क है।
किसी संपत्ति तक पहुंचने का एकमात्र तरीका यदि वह private
है तो उसे उस दायरे से एक्सेस किया जाता है जो उसे अनुमति देता है, अर्थात। कक्षा का दायरा। केवल पिछले कोड उदाहरण में, स्कोप निर्दिष्ट नहीं किया गया है, जिसका अर्थ है कि क्लोजर को उसी स्कोप में इनवॉइस किया गया है जैसे कि जहां पर क्लोजर बनाया गया है। आइए इसे बदलते हैं:
<?php
$myClosure = function() {
echo $this->property;
};
class MyClass
{
private $property; // $property is now private
public function __construct($propertyValue)
{
$this->property = $propertyValue;
}
}
$myInstance = new MyClass('Hello world!');
$myBoundClosure = $myClosure->bindTo($myInstance, MyClass::class);
$myBoundClosure(); // Shows "Hello world!"
जैसा कि अभी कहा गया है, यदि इस दूसरे पैरामीटर का उपयोग नहीं किया जाता है, तो क्लोजर को उसी संदर्भ में लागू किया जाता है, जैसा कि उपयोग किया गया है, जहां क्लोजर बनाया गया है। उदाहरण के लिए, किसी विधि के वर्ग के अंदर बनाया गया एक क्लोजर जो किसी ऑब्जेक्ट संदर्भ में लगाया जाता है, उसकी विधि के समान गुंजाइश होगी:
<?php
class MyClass
{
private $property;
public function __construct($propertyValue)
{
$this->property = $propertyValue;
}
public function getDisplayer()
{
return function() {
echo $this->property;
};
}
}
$myInstance = new MyClass('Hello world!');
$displayer = $myInstance->getDisplayer();
$displayer(); // Shows "Hello world!"
एक कॉल के लिए एक बंधन बांधना
PHP7 के बाद से , केवल एक कॉल के लिए एक बंद को बांधना संभव है, call
विधि के लिए धन्यवाद। उदाहरण के लिए:
<?php
class MyClass
{
private $property;
public function __construct($propertyValue)
{
$this->property = $propertyValue;
}
}
$myClosure = function() {
echo $this->property;
};
$myInstance = new MyClass('Hello world!');
$myClosure->call($myInstance); // Shows "Hello world!"
जैसा कि bindTo
पद्धति का विरोध है, चिंता की कोई गुंजाइश नहीं है। इस कॉल के लिए उपयोग किया जाने वाला दायरा वही है जिसका उपयोग $myInstance
की संपत्ति तक पहुँचने या आह्वान करने के दौरान किया जाता है।
प्रेक्षक पैटर्न को लागू करने के लिए क्लोजर का उपयोग करें
सामान्य तौर पर, एक पर्यवेक्षक एक विशिष्ट पद्धति वाला एक वर्ग होता है जिसे तब देखा जाता है जब अवलोकन की गई वस्तु पर कोई क्रिया होती है। कुछ स्थितियों में, प्रेक्षक डिजाइन पैटर्न को लागू करने के लिए क्लोजर पर्याप्त हो सकता है।
इस तरह के कार्यान्वयन का एक विस्तृत उदाहरण यहां दिया गया है। आइए पहले एक वर्ग की घोषणा करें जिसका उद्देश्य पर्यवेक्षकों को सूचित करना है जब इसकी संपत्ति बदल दी जाती है।
<?php
class ObservedStuff implements SplSubject
{
protected $property;
protected $observers = [];
public function attach(SplObserver $observer)
{
$this->observers[] = $observer;
return $this;
}
public function detach(SplObserver $observer)
{
if (false !== $key = array_search($observer, $this->observers, true)) {
unset($this->observers[$key]);
}
}
public function notify()
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
public function getProperty()
{
return $this->property;
}
public function setProperty($property)
{
$this->property = $property;
$this->notify();
}
}
फिर, आइए उस वर्ग की घोषणा करें जो विभिन्न पर्यवेक्षकों का प्रतिनिधित्व करेगा।
<?php
class NamedObserver implements SplObserver
{
protected $name;
protected $closure;
public function __construct(Closure $closure, $name)
{
$this->closure = $closure->bindTo($this, $this);
$this->name = $name;
}
public function update(SplSubject $subject)
{
$closure = $this->closure;
$closure($subject);
}
}
आइए अंत में इसका परीक्षण करें:
<?php
$o = new ObservedStuff;
$observer1 = function(SplSubject $subject) {
echo $this->name, ' has been notified! New property value: ', $subject->getProperty(), "\n";
};
$observer2 = function(SplSubject $subject) {
echo $this->name, ' has been notified! New property value: ', $subject->getProperty(), "\n";
};
$o->attach(new NamedObserver($observer1, 'Observer1'))
->attach(new NamedObserver($observer2, 'Observer2'));
$o->setProperty('Hello world!');
// Shows:
// Observer1 has been notified! New property value: Hello world!
// Observer2 has been notified! New property value: Hello world!
ध्यान दें कि यह उदाहरण काम करता है क्योंकि पर्यवेक्षक एक ही प्रकृति को साझा करते हैं (वे दोनों "पर्यवेक्षक नामित हैं।"