পিএইচপি: হিন্টিং টাইপ করুন - los ক্লোজার` এবং `কল্যাবলের মধ্যে পার্থক্য`


128

আমি লক্ষ্য করেছি যে আমরা যদি কিছু কলব্যাক ফাংশনটি চালানোর জন্য প্রত্যাশা করি তবে আমি উভয়ই Closureবা Callableটাইপ ইঙ্গিত হিসাবে ব্যবহার করতে পারি। উদাহরণ স্বরূপ:

function callFunc1(Closure $closure) {
    $closure();
}

function callFunc2(Callable $callback) {
    $callback();
}

$function = function() {
    echo 'Hello, World!';
};

callFunc1($function); // Hello, World!
callFunc2($function); // Hello, World!

প্রশ্ন:

এখানে পার্থক্য কি? অন্য কথায় কখন ব্যবহার করবেন Closureএবং কখন ব্যবহার করবেন Callableবা তারা একই উদ্দেশ্যে কাজ করবে?

উত্তর:


173

পার্থক্যটি হ'ল এটি Closureঅবশ্যই একটি বেনামি ফাংশন হতে হবে, যেখানে callableসাধারণ ফাংশনও হতে পারে।

আপনি নীচের উদাহরণ সহ এটি দেখতে / পরীক্ষা করতে পারেন এবং আপনি দেখতে পাবেন যে আপনি প্রথমটির জন্য একটি ত্রুটি পাবেন:

function callFunc1(Closure $closure) {
    $closure();
}

function callFunc2(Callable $callback) {
    $callback();
}

function xy() {
    echo 'Hello, World!';
}

callFunc1("xy"); // Catchable fatal error: Argument 1 passed to callFunc1() must be an instance of Closure, string given
callFunc2("xy"); // Hello, World!

সুতরাং আপনি যদি কেবল ইঙ্গিত বেনামে ফাংশন ব্যবহার টাইপ Closureকরতে চান : এবং আপনি যদি চান তবে সাধারণ ফাংশনগুলি callableহিন্ট টাইপ হিসাবে ব্যবহার করতে অনুমতি দিন ।


5
আপনি অ্যারে পাস করে কলযোগ্য সহ ক্লাসের পদ্ধতিগুলিও ব্যবহার করতে পারেন, যেমন: ["Foo", "bar"]জন্য Foo::barবা এর [$foo, "bar"]জন্য $foo->bar
Andrea

17
Offtopic কিন্তু সম্পর্কিত: পিএইচপি 7.1 যেহেতু, আপনি এখন সহজেই একটি বন্ধ রূপান্তর করতে পারেন: callFunc1(Closure::fromCallable("xy"))wiki.php.net/rfc/closurefromcallable
nevvermind

আমি এখনও দেখছি না কেন আমি কেবল বেনামে ফাংশনটি কল করতে চাই। আমি যদি কোডটি ভাগ করে নিই তবে ফাংশনটি কোথা থেকে আসে সেদিকে আমার চিন্তা করা উচিত নয়। আমি বিবেচনা করি যে পিএইচপি'র একটি তিরস্কার, তাদের বিভ্রান্তি এড়াতে এক বা অন্য উপায় সরিয়ে ফেলা উচিত। তবে আমি সত্যিই Closure+ Closure::fromCallableপদ্ধতির পছন্দ করি কারণ স্ট্রিং বা অ্যারে যেমন callableসর্বদা অদ্ভুত।
রোবো রোবক

2
@ রোবরোবোকের কেবলমাত্র Closure(বেনামে ফাংশন) প্রয়োজনের এক কারণ হিসাবে callableবলা হয়, ডাকা ফাংশনটির পরিধি ছাড়িয়ে যাওয়া রোধ করা। উদাহরণস্বরূপ, যখন আপনার একটি থাকে তখন আপনি private methodকোনও এটিকে আপত্তিজনক ব্যবহার করে অ্যাক্সেস করতে চান না callable। দেখুন: 3v4l.org/7TSf2
fyrye

58

তাদের মধ্যে প্রধান পার্থক্য closureহ'ল ক একটি শ্রেণি এবং callableএক প্রকার

callableটাইপ কিছু করা যেতে পারে গ্রহণ নামক :

var_dump(
  is_callable('functionName'),
  is_callable([$myClass, 'methodName']),
  is_callable(function(){})
);

যেখানে একজন কেবল একটি বেনামি ফাংশন গ্রহণ closureকরবে । মনে রাখবেন যে, পিএইচপি সংস্করণ 7.1 মধ্যে আপনি এখন মত একটি অবসান ফাংশন রূপান্তর করতে পারেন: ।Closure::fromCallable('functionName')


উদাহরণ:

namespace foo{
  class bar{
    private $val = 10;

    function myCallable(callable $cb){$cb()}
    function myClosure(\Closure $cb){$cb()} // type hint must refer to global namespace
  }

  function func(){}
  $cb = function(){};
  $fb = new bar;

  $fb->myCallable(function(){});
  $fb->myCallable($cb);
  $fb->myCallable('func');

  $fb->myClosure(function(){});
  $fb->myClosure($cb);
  $fb->myClosure(\Closure::fromCallable('func'));
  $fb->myClosure('func'); # TypeError
}

সুতরাং কেন একটি closureওভার ব্যবহারcallable ?

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

$inject = function($i){return $this->val * $i;};
$cb1 = Closure::bind($inject, $fb);
$cb2 = $inject->bindTo($fb);

echo $cb1->call($fb, 2); // 20
echo $cb2(3);            // 30

আপনি কোনও সাধারণ ক্রিয়াকলাপগুলিতে কল করতে পছন্দ করেন না কারণ এটি মারাত্মক ত্রুটি বাড়িয়ে তুলবে। সুতরাং আপনি যাতে কিছু লিখতে হবে তা রোধ করার জন্য:

if($cb instanceof \Closure){}

প্রতিবার এই চেকটি করা অর্থহীন। সুতরাং আপনি যদি এই পদ্ধতিগুলি ব্যবহার করতে চান তবে যুক্তিটি হ'ল একটি closure। অন্যথায় শুধু একটি সাধারণ ব্যবহার করুন callback। এই পথে; আপনার কোডের পরিবর্তে ফাংশন কলে একটি ত্রুটি উত্থাপিত হয় যার ফলে এটি নির্ণয় করা আরও সহজ হয়ে যায়।

একটি পার্শ্ব নোট অন:closure বর্গ তার যেমন বাড়ানো যাবে না চূড়ান্ত


1
আপনি অন্য স্কোপগুলিতে কলযোগ্যকে আবারও ব্যবহার করতে পারেন।
বিমল পাউদেল

এর অর্থ আপনাকে callableকোনও নেমস্পেসে যোগ্যতা অর্জন করতে হবে না ।
জেফ পেকেট

0

এটি উল্লেখযোগ্য যে এটি পিএইচপি সংস্করণ 5.3.21 থেকে 5.3.29 এর জন্য কাজ করবে না।

এই সংস্করণগুলির যে কোনওটিতে আপনি একটি আউটপুট পাবেন:

ওহে বিশ্ব! ধরা পড়ার জন্য মারাত্মক ত্রুটি: কলটিফাঁকে 2 এ আর্গুমেন্ট 1টি পাস হয়েছে (কল করা) এর উদাহরণ হতে হবে, বন্ধ করার উদাহরণ দেওয়া হয়েছে, লাইন 16-এ / ইন / কেকিওয়াইডি কল করা হবে এবং লাইন 7-এ / ইন / কেকিওয়াইডি-তে সংজ্ঞায়িত করা হবে

255 কোড সহ প্রক্রিয়াটি প্রস্থান করা হয়েছে।

Https://3v4l.org/kqeYD#v5321 ব্যবহার করে কেউ চেষ্টা করে দেখতে পারেন

শুভেচ্ছান্তে,


2
কোডটিতে কোনও লিঙ্ক পোস্ট করার পরিবর্তে, অন্য কেউ যদি এই সমস্যায় পড়ে এবং আপনি যে লিঙ্কটি সরবরাহ করেছিলেন তাতে বিরতি ঘটে তবে আপনার কোডটি এখানে পোস্ট করা উচিত। আপনি সাহায্যের জন্য আপনার পোস্টে আউটপুট সরবরাহ করতে পারেন।
বেদদা

5
এটি কারণ callableপিএইচপি 5.4 এ চালু হয়েছিল। যে পিএইচপি এর আগে নামে একজন ক্লাসের একটা নিদর্শন আশা করছে callable, শুধু যেন আপনার জন্য একটি ইঙ্গিতটি নিদিষ্ট চাই PDO, DateTimeঅথবা \My\Random\ClassName
ডেভি শফিক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.