কলিং ক্লজার অবজেক্ট সম্পত্তি সরাসরি বরাদ্দ করা


109

আমি কোনও ভেরিয়েবলের কাছে ক্লোজারটিকে পুনরায় স্বাক্ষর না করে এবং তারপরে কল না করেই কোনও অবজেক্টের সম্পত্তিতে সরাসরি অর্পিত এমন একটি ক্লোজার কল করতে সক্ষম হতে চাই। এটা কি সম্ভব?

নীচের কোডটি কাজ করে না এবং কারণগুলিও নয় Fatal error: Call to undefined method stdClass::callback()

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

1
আপনার ঠিক এটির প্রয়োজন: github.com/ptrofimov/jslikeobject আরও বেশি: আপনি এটি ব্যবহার করতে পারেন - বন্ধ হয়ে যাওয়ার পরে এবং উত্তরাধিকার ব্যবহার করতে পারেন। কেবল পিএইচপি> = 5.4!
রেনাটো কচিনোত্তো

উত্তর:


106

পিএইচপি 7 হিসাবে, আপনি করতে পারেন

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

বা বন্ধ করুন :: কল () ব্যবহার করুন , যদিও এটি একটিতে কাজ করে না StdClass


পিএইচপি 7 এর আগে আপনাকে কলটি বন্ধ করতে এবং কলব্যাকটি __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
কখনও কখনও আপনি এই বাক্য গঠনটি ব্যবহারকারীর পুরোটি দেখতে পাবেন - কল_ইউজার_ফুঙ্ক_আরে ($ এটি -> $ সম্পত্তি, $ আরগস); যখন এটি কলযোগ্য শ্রেণীর সম্পত্তি সম্পর্কে হয়, কোনও পদ্ধতি নয়।
নিকিতা গোপকালো

104

আপনি ক্লোজারে __ ইনভোক কল করে এটি করতে পারেন, যেহেতু এটি সেই যাদু পদ্ধতি যা ফাংশনগুলির মতো আচরণ করার জন্য অবজেক্টগুলি ব্যবহার করে:

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

অবশ্যই এটি কাজ করবে না যদি কলব্যাকটি একটি অ্যারে বা একটি স্ট্রিং (যা পিএইচপি-তে বৈধ কলব্যাকও হতে পারে) - কেবল ক্লোজার এবং অন্যান্য আইটেমগুলির জন্য __inocke আচরণের সাথে।


3
@ মার্সিওআলমদা যদিও খুব কুরুচিপূর্ণ।
মাহন

1
@ মাহন আমি মনে করি এটি গৃহীত উত্তরের চেয়ে আরও সুস্পষ্ট। স্পষ্টত এই ক্ষেত্রে ভাল। আপনি যদি সত্যিই একটি "চতুর" সমাধানের জন্য যত্নবান হন তবে call_user_func($obj->callback)এটি খারাপ নয়।
মার্সিও

তবে call_user_funcস্ট্রিংগুলির সাথেও কাজ করে এবং এটি সর্বদা বিশ্বাসযোগ্য নয়
ঘেরম্যান

2
@cerebriform শব্দার্থগতভাবে এটা কোন অর্থে যা করতে হবে করে তোলে $obj->callback->__invoke();যখন কেউ এটা হতে আশা $obj->callback()। এটি কেবল ধারাবাহিকতার প্রশ্ন।
মাহন

3
@ মাহান: মঞ্জুর, এটি ধারাবাহিক নয়। যদিও ধারাবাহিকতা সত্যই কখনও পিএইচপি শক্তিশালী মামলা ছিল না। :) কিন্তু আমি মনে করি যখন এক বস্তু প্রকৃতি বিবেচনা করে এটা তোলে ইন্দ্রিয় আছে: $obj->callback instanceof \Closure
বিশপ

24

পিএইচপি 7 হিসাবে আপনি নিম্নলিখিত করতে পারেন:

($obj->callback)();

এ জাতীয় সাধারণ জ্ঞান, তবু এটি নিখুঁতভাবে খারাপ। পিএইচপি 7 এর দুর্দান্ত শক্তি!
tfont

10

পিএইচপি 7 যেহেতু call()পদ্ধতিটি ব্যবহার করে একটি ক্লোজার বলা যেতে পারে :

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

যেহেতু পিএইচপি 7 স্বেচ্ছাসেবী (...)মত প্রকাশের উপরও ক্রিয়াকলাপ চালানো সম্ভব ( কোরিকুলাম ব্যাখ্যা করেছেন ):

($obj->callback)();

অন্যান্য সাধারণ পিএইচপি 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);

মার্জিত নয়, যদিও .... গর্ডন যা বলেন সম্ভবত এটিই কেবল একমাত্র উপায়।


7

আচ্ছা, যদি আপনি সত্যিই জেদ করেন। আর একটি কাজ হবে:

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

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

$obj['callback']();

তবে এটি সেরাতম বাক্য গঠন নয়।

যাইহোক, পিএইচপি পার্সার সবসময় একইরূপে T_OBJECT_OPERATOR, IDENTIFIER, (পদ্ধতি কল হিসাবে। ->পদ্ধতি টেবিলকে বাইপাস তৈরি করার পরিবর্তে বৈশিষ্ট্যগুলিতে অ্যাক্সেসের পক্ষে কোনও কার্যকর নেই বলে মনে হচ্ছে ।


7

আমি জানি এটি পুরানো, তবে আমি মনে করি আপনি যদি পিএইচপি 5.4+ ব্যবহার করেন তবে বৈশিষ্ট্যগুলি সুন্দরভাবে এই সমস্যাটি পরিচালনা করে

প্রথমে এমন একটি বৈশিষ্ট্য তৈরি করুন যা বৈশিষ্ট্যগুলিকে কলযোগ্য করে তোলে:

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

ধন্যবাদ :)। এটি সম্ভবত অস্পষ্টতার কারণেই এটি নির্মিত হয়নি। আমার উদাহরণে কল্পনা করুন, যদি সেখানে আসলে "অ্যাড" নামে একটি ফাংশন এবং "অ্যাড" নামে পরিচিত একটি সম্পত্তি ছিল। প্রথম বন্ধনী উপস্থিতি পিএইচপি কে সেই নামের সাথে কোনও ফাংশন সন্ধান করতে বলে।
স্টিভেক

2

ঠিক আছে, এটি জোর দিয়ে বলা উচিত যে একটি পরিবর্তনশীলতে ক্লোজারটি সংরক্ষণ করা হয় এবং ভেরিয়েবলটি কল করা হয় প্রকৃতপক্ষে (বিস্মৃতভাবে) দ্রুত, কল পরিমাণের উপর নির্ভর করে, এটি বেশ অনেকটা হয়ে যায়, xdebug সহ (তাই খুব নির্ভুল পরিমাপ), আমরা কথা বলছি 1,5 (ফ্যাক্টর, একটি ভেরিয়েবল ব্যবহার করে, সরাসরি __invoke কল করার পরিবর্তে so সুতরাং পরিবর্তে, কেবল একটি পরিবর্তনশীলটিতে ক্লোজারটি সংরক্ষণ করুন এবং কল করুন।


2

আপডেট করা হয়েছে:

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

পিএইচপি> = 7:

($obj->callback)();

পিএইচপি> = 5.4:

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

আপনি কি এই চেষ্টা করেছেন? এটি কাজ করে না। Call to undefined method AnyObject::callback()(ক্লাস যেকোনওবজেক্ট অবশ্যই বিদ্যমান))
কনট্রলফ্র্যাক

1

স্বীকৃত উত্তরের উপর ভিত্তি করে এখানে আরও একটি বিকল্প রয়েছে তবে স্টাডক্লাস সরাসরি প্রসারিত:

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

আপনি যদি পিএইচপি 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 এ কাজ করে works

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

একটিকে ক্লোজারগুলির একটি পিচিউডো-অবজেক্ট সংগ্রহ তৈরি করার অনুমতি দেয়।

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