सीधे ऑब्जेक्ट ऑब्जेक्ट को असाइन किए गए कॉलिंग को बंद करना


109

मैं एक क्लोजर को कॉल करने में सक्षम होना चाहूंगा जो मैं किसी ऑब्जेक्ट की प्रॉपर्टी को सीधे एक वैरिएबल को रि-साइन किए बिना और फिर उसे कॉल करने के लिए असाइन करता हूं। क्या यह संभव है?

नीचे दिया गया कोड काम नहीं करता है और इसका कारण बनता है Fatal error: Call to undefined method stdClass::callback()

$obj = new stdClass();
$obj->callback = function() {
    print "HelloWorld!";
};
$obj->callback();

1
यह वही है जो आपको चाहिए: github.com/ptrofimov/jslikeobject इससे भी अधिक: आप इसे क्लोज़र के अंदर $ का उपयोग कर सकते हैं और वंशानुक्रम का उपयोग कर सकते हैं। केवल PHP> = 5.4!
रेनाटो क्यूकेनटोटोन

जवाबों:


106

PHP7 के रूप में, आप कर सकते हैं

$obj = new StdClass;
$obj->fn = function($arg) { return "Hello $arg"; };
echo ($obj->fn)('World');

या बंद का उपयोग करें :: कॉल () , हालांकि यह एक पर काम नहीं करता है StdClass


PHP7 से पहले, आपको __callकॉल को इंटरसेप्ट करने और कॉलबैक को लागू करने के लिए मैजिक विधि को लागू करना होगा (जो कि StdClassनिश्चित रूप से संभव नहीं है , क्योंकि आप __callविधि को जोड़ नहीं सकते हैं )

class Foo
{
    public function __call($method, $args)
    {
        if(is_callable(array($this, $method))) {
            return call_user_func_array($this->$method, $args);
        }
        // else throw exception
    }
}

$foo = new Foo;
$foo->cb = function($who) { return "Hello $who"; };
echo $foo->cb('World');

ध्यान दें कि आप ऐसा नहीं कर सकते

return call_user_func_array(array($this, $method), $args);

में __callशरीर, क्योंकि इस ट्रिगर करेगा __callअनंत लूप में।


2
कभी-कभी आपको यह सिंटैक्स उपयोगी मिलेगा - call_user_func_array ($ यह -> $ संपत्ति, $ $); जब यह कॉल करने योग्य वर्ग की संपत्ति के बारे में है, तो एक विधि नहीं।
निकिता गोपालको

105

आप इसे बंद करने के लिए __invoke पर कॉल करके कर सकते हैं, क्योंकि यह जादू की विधि है जिसका उपयोग वस्तुएं कार्य करने के लिए करती हैं:

$obj = new stdClass();
$obj->callback = function() {
    print "HelloWorld!";
};
$obj->callback->__invoke();

निश्चित रूप से यह काम नहीं करेगा यदि कॉलबैक एक सरणी या स्ट्रिंग है (जो PHP में वैध कॉलबैक भी हो सकती है) - सिर्फ __inoke व्यवहार के साथ क्लोजर और अन्य ऑब्जेक्ट के लिए।


3
@marcioAlmada हालांकि बहुत बदसूरत है।
Mahn

1
@ मुझे लगता है कि यह स्वीकृत उत्तर की तुलना में अधिक स्पष्ट है। इस मामले में स्पष्ट बेहतर है। यदि आप वास्तव में "प्यारा" समाधान की परवाह करते हैं, तो call_user_func($obj->callback)क्या यह बुरा नहीं है।
marcio

लेकिन call_user_funcतार के साथ भी काम करता है और यह हमेशा आश्वस्त नहीं होता है
घर्मन

2
@ सेरेब्रिफ़ॉर्म शब्दार्थ से कोई मतलब नहीं है कि $obj->callback->__invoke();जब कोई ऐसा करने की उम्मीद करेगा $obj->callback()। यह सिर्फ स्थिरता का सवाल है।
महेन

3
@ मेन: दी, यह सुसंगत नहीं है। संगति वास्तव में PHP मजबूत सूट कभी नहीं किया गया है, हालांकि। :) लेकिन मुझे लगता है कि यह समझ में आता है, जब कोई वस्तु प्रकृति पर विचार करता है $obj->callback instanceof \Closure:।
बिशप

24

के रूप में पीएचपी 7 आप निम्नलिखित कर सकते हैं:

($obj->callback)();

ऐसा सामान्य ज्ञान, फिर भी यह विशुद्ध रूप से बदमाश है। PHP7 की महान शक्ति!
tfont

10

PHP 7 के बाद से एक बंद call()विधि का उपयोग करके बुलाया जा सकता है :

$obj->callback->call($obj);

चूंकि PHP 7 में मनमाने ढंग से (...)भावों पर भी संचालन करना संभव है (जैसा कि कोरिकुलम द्वारा समझाया गया है ):

($obj->callback)();

अन्य सामान्य PHP 5 दृष्टिकोण हैं:

  • जादू पद्धति का उपयोग करना __invoke()(जैसा कि ब्रिलियन द्वारा समझाया गया है )

    $obj->callback->__invoke();
  • call_user_func()फ़ंक्शन का उपयोग करना

    call_user_func($obj->callback);
  • एक अभिव्यक्ति में एक मध्यवर्ती चर का उपयोग करना

    ($_ = $obj->callback) && $_();

प्रत्येक तरीके के अपने स्वयं के पेशेवरों और विपक्ष हैं, लेकिन सबसे कट्टरपंथी और निश्चित समाधान अभी भी गॉर्डन द्वारा प्रस्तुत किया गया है ।

class stdKlass
{
    public function __call($method, $arguments)
    {
        // is_callable([$this, $method])
        //   returns always true when __call() is defined.

        // is_callable($this->$method)
        //   triggers a "PHP Notice: Undefined property" in case of missing property.

        if (isset($this->$method) && is_callable($this->$method)) {
            return call_user_func($this->$method, ...$arguments);
        }

        // throw exception
    }
}

$obj = new stdKlass();
$obj->callback = function() { print "HelloWorld!"; };
$obj->callback();

7

इसका उपयोग संभव प्रतीत हो रहा है call_user_func()

call_user_func($obj->callback);

सुरुचिपूर्ण नहीं है, हालांकि .... जो @Gordon कहता है वह शायद जाने का एकमात्र तरीका है।


7

खैर, अगर आप वास्तव में जोर देते हैं। एक और समाधान होगा:

$obj = new ArrayObject(array(),2);

$obj->callback = function() {
    print "HelloWorld!";
};

$obj['callback']();

लेकिन यह सबसे अच्छा वाक्यविन्यास नहीं है।

हालांकि, PHP पदव्याख्यायित्र हमेशा व्यवहार करता है T_OBJECT_OPERATOR, IDENTIFIER, (विधि कॉल के रूप में। लगता है ->कि विधि तालिका को बायपास करने और इसके बजाय विशेषताओं तक पहुंचने के लिए कोई समाधान नहीं है ।


7

मुझे पता है कि यह पुराना है, लेकिन मुझे लगता है कि यदि आप PHP 5.4+ का उपयोग कर रहे हैं तो Traits अच्छी तरह से इस समस्या को संभालते हैं

सबसे पहले, एक गुण बनाएँ जो गुणों को कॉल करने योग्य बनाता है:

trait CallableProperty {
    public function __call($method, $args) {
        if (property_exists($this, $method) && is_callable($this->$method)) {
            return call_user_func_array($this->$method, $args);
        }
    }
}

फिर, आप अपनी कक्षाओं में उस विशेषता का उपयोग कर सकते हैं:

class CallableStdClass extends stdClass {
    use CallableProperty;
}

अब, आप बेनामी कार्यों के माध्यम से संपत्तियों को परिभाषित कर सकते हैं और उन्हें सीधे कॉल कर सकते हैं:

$foo = new CallableStdClass();
$foo->add = function ($a, $b) { return $a + $b; };
$foo->add(2, 2); // 4

वाह :) यह बहुत अधिक सुरुचिपूर्ण है जो मैं करने की कोशिश कर रहा था। मेरा एकमात्र सवाल ब्रिटिश हॉट / कोल्ड टैप कनेक्टर तत्वों के लिए समान है: यह पहले से क्यों नहीं बनाया गया है ??
dkellner

धन्यवाद :)। यह शायद इसकी अस्पष्टता के कारण नहीं बनाया गया है। मेरे उदाहरण में कल्पना कीजिए, अगर वास्तव में "ऐड" नामक एक फ़ंक्शन और "ऐड" नामक एक संपत्ति थी। कोष्ठक की उपस्थिति PHP को उस नाम के साथ एक फ़ंक्शन देखने के लिए कहती है।
स्टीवके

2

ठीक है, यह स्पष्ट किया जाना चाहिए कि एक चर में बंद भंडारण, और चर को बुलाओ वास्तव में (wierdly) तेजी से, कॉल राशि के आधार पर, यह काफी हो जाता है, xdebug (बहुत सटीक माप) के साथ, हम बात कर रहे हैं 1,5, कारक, एक चर का उपयोग करके, सीधे __invoke को कॉल करने के बजाय। इसलिए इसके बजाय, बस एक संस्करण में बंद को स्टोर करें और इसे कॉल करें।


2

अपडेट किया गया:

$obj = new stdClass();
$obj->callback = function() {
     print "HelloWorld!";
};

PHP> = 7:

($obj->callback)();

PHP> = 5.4:

$callback = $obj->callback;  
$callback();

क्या आपने यह कोशिश की? यह काम नहीं करता है। Call to undefined method AnyObject::callback()(कक्षा AnyObject निश्चित रूप से मौजूद है।)
Kontrollfreak

1

यहाँ एक अन्य विकल्प है जो स्वीकृत उत्तर पर आधारित है, लेकिन सीधे stdClass का विस्तार कर रहा है:

class stdClassExt extends stdClass {
    public function __call($method, $args)
    {
        if (isset($this->$method)) {
            $func = $this->$method;
            return call_user_func_array($func, $args);
        }
    }
}

उपयोग उदाहरण:

$foo = new stdClassExt;
$foo->blub = 42;
$foo->whooho = function () { return 1; };
echo $foo->whooho();

आप शायद बेहतर उपयोग कर रहे हैं call_user_funcया __invokeयद्यपि।


0

यदि आप PHP 5.4 या इसके बाद के संस्करण का उपयोग कर रहे हैं, तो आप कस्टम व्यवहार को लागू करने के लिए अपने ऑब्जेक्ट के दायरे में एक कॉल करने योग्य बांध सकते हैं। तो उदाहरण के लिए यदि आप निम्नलिखित सेट अप करने के लिए थे ..

function run_method($object, Closure $method)
{
    $prop = uniqid();
    $object->$prop = \Closure::bind($method, $object, $object);
    $object->$prop->__invoke();
    unset($object->$prop);
}

और तुम एक कक्षा पर काम कर रहे थे जैसे ..

class Foo
{
    private $value;
    public function getValue()
    {
        return $this->value;
    }
}

आप अपना तर्क चला सकते हैं जैसे कि आप अपनी वस्तु के दायरे में काम कर रहे थे

$foo = new Foo();
run_method($foo, function(){
    $this->value = 'something else';
});

echo $foo->getValue(); // prints "something else"

0

मैं ध्यान देता हूं कि यह PHP5.5 में काम करता है

$a = array();
$a['callback'] = function() {
    print "HelloWorld!";
};
$a['callback']();

एक को बंद करने के एक psuedo- वस्तु संग्रह बनाने के लिए अनुमति देता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.