توابع ناشناس – anonymous

توابع ناشناخته که اصطلاحا به آن‌ها تابع روی هوا (on the fly) گفته می شود، به طور ساده تابعی است بدون‌نام. مانند مثال زیر:

<?php
// Anonymous function

function () {
  return "Hello world";
}
این مفهوم در PHP تحت قالب Lambda وClosures پیاده سازی شده است. در ادامه مطلب بیشتر به این مورد خواهیم پرداخت.
  • توابع Lambada

یک Lambada تابع ناشناخته‌ای است که به یک متغیر انتساب داده می شود و یا به عنوان پارامتر به تابع دیگر انتساب داده می‌شود.

  • استفاده از Lambada

از آن جا که این مدل از تابع‌ها نام ندارند، پس شما نمی‌توانید مثل تابع‌های معمولی آن‌ها را صدا بزنید. بلکه باید همینطور که قبلا به آن اشاره شد، تابع را به یک متغیر انتساب بدهید و یا به عنوان پارامتر به تابع دیگری ارسال کنید.

<?php
// Anonymous function

// assigned to variable
$greeting = function ($world = '') {
  return "Hello". $world;
};

// Call function
echo $greeting('world');

// Returns "Hello world"

نکته:همینطور که در کد بالا هم مشاهده می کنید، سمی کالن (;) را بعد از اتمام تابع قرار می‌دهیم.

نکته:همینطور که در کد بالا هم مشاهده می کنید، می‌توانیم پارامتر به صورت دلخواه به تابع بدهیم (world$).

به منظور استفاده از تابع ناشناخته، ما این تابع را به یک متغیر انتساب میدهیم و سپس متغیر را به عنوان یک تابع، Call یا صدا میزنیم.

شما همچنین می‌توانید Lambadaایی که تعریف کرده‌اید را به عنوان پارامتر به تابع دیگر بفرستید:

<?php
// Pass Lambda to function

function shout ($message) {
  echo $message();
}


// Call function
shout(function() {
  return "Hello world";
});
برای چی من باید از Lambada استفاده کنم؟

شاید الان با خودتان گفتید که این تابع بدون اسم چه زمانی کارایی دارد؟

Lambada از تعریف تابع هایی که معمولا کد کوچک و مختصری دارند و ممکن است شما در طول اجرای برنامه، مثلا، فقط یکبار صدا بزنید، خودداری می کند. اغلب شما، به تابعی نیاز دارید که کاری را برای شما انجام دهد، اما این نیاز را پیدا نمی کنید که آن را داخل global scope برنامه یا حتی به عنوان بخشی از بقیه کدها اضافه کنید.

به جای اینکه تابعی داشته باشید که یک بار استفاده و بعد هم رها شود، میتوانید از Lambada استفاده کنید.

یک مورد پر استفاده دیگر توابع ناشناخته درfunction callbackها است.

اگر مفهوم توابع callback در PHP را نمی‌دانید، یک جستجو راجع به آن انجام دهید، چرا که شرح کامل آن در این بحث نمی گنجد. اما یک نگاه سطحی با یک مثال به آن می‌اندازیم تا بحث بیشتر برایتان روشن شود.

Callback هر تابعی که صدا زده شده است توسط تابع دیگری که البته آن تابع دیگر، تابع اول را به عنوان پارامتر میگیرد و Call می‌کند. معمولا callback تابعی است که زمانی صدا زده می‌شود که اتفاقی رخ داده باشد، که در دنیای برنامه نویسی به آن اتفاق، رویداد یا event گفته میشود.

مثال زیر یک مثال پایه‌ایی از تابع‌های callback است:

شما می‌توانید تابعی که نامش در یک متغیر ذخیره شده است را call کنید. فقط کافیست به انتهای نام متغیر، پرانتز باز و بسته () اضافه کنید. مثل ()variable$

<?php
function thisFuncTakesACallback($callbackFunc)
{

  echo "I'm going to call $callbackFunc!";

  $callbackFunc();

}

function thisFuncGetsCalled()
{
  echo "I'm a callback function!";
}

thisFuncTakesACallback( 'thisFuncGetsCalled' );
خب در مثال بالا، ما نام تابع thisFuncGetsCalled را به تابع ()thisFuncTakesACallback ارسال کردیم که سپس این تابع، تابعی که به آن فرستاده شده بود رو صدا زد.

از توابع ناشناخته در توابع بومی PHP استفاده شده، که مثال‌های فوق العاده‌ای در این زمینه هستند، از جمله array_walkarray_maparray_reduce و array_filter usort.

در مثال زیر نمونه‌ایی از callback function را مشاهده می‌کنید که با Lambada و در تابع array_filter پیاده سازی شده است.

نکته: کار array_filter به این صورت است که پارامتر اول یک آرایه مثلا input$ را می‌گیرد و در یک Loop قرار می‌دهد و هر دفعه مقدار فعلی آرایه را به function callback ارسال یا pass میکند. اگرfunction callback مقدار true برگرداند، value جاری خانه مورد نظر از آرایه برگردانده می‌شود. در ضمن keyهای آرایه هم تغییری نمی‌کنند.

<?php
$input = array(1, 2, 3, 4, 5);

$output = array_filter($input, function ($v) { return $v > 2; });

// $output == array(2 => 3, 3 => 4, 4 => 5)
در مثال بالا، آرایه ورودی فیلتر می‌شود؛ به طوریکه تمام اعداد بزرگتر از 2 استخراج می‌شوند.

در مثال بالا، عبارت { ;function ($v) { return $v > 2 یک Lambada است، که اگر میخواهید قابل استفاده مجدد باشد باید آن را داخل یک متغیر ذخیره کنید.

اطلاعات بیشتر:

پیشتر می‌توانستید از create_function در PHP استفاده کنید که اساسا همین کار را انجام میدهد.

<?php
// Use create_function

$greeting = create_function('', 'echo "Hello World!";');



// Call function
$greeting();

توابع Closure

یک Closure (کلوژر) اساسا همان Lambada است، علاوه بر اینکه، می‌توانید به متغیرهای خارج از محدوده‌ایی که تعریف شده هم، دسترسی داشته باشد.

<?php
// Create a user

$user = "Philip";

// Create a Closure

$greeting = function() use ($user) {

  echo "Hello $user";

};

// Greet the user
$greeting(); // Returns "Hello Philip"
همان طور که در بالا می بینید Closure می‌تواند به متغیر user$ دسترسی داشته باشد، به این دلیل که در عبارت use، تعریف تابع Closure آورده شده است.

همچنین اگر می‌خواهید مقدار متغیر user$ را داخل Closure تغییر بدهید و بیرون آن هم این تغییر از بین نرود، باید حتما قبل از متغیر داخل عبارت use یک & (امپرسند) قرار بدهید تا متغیر به صورت ارسال با مرجع فرستاده شود.

بیایید مثال array_filter را نیز با Closure انجام بدهیم.

<?php
$max_comparator = function ($max)
{
  return function ($v) use ($max) { return $v > $max; };
};

$input = array(1, 2, 3, 4, 5);

$output = array_filter($input, $max_comparator(3)); // Array ( [3] => 4 [4] => 5 )
در مثال بالا دو نکته را دیدید که یکی استفاده از توابع ناشناخته بصورت تودرتو و دیگری اینکه max$ به عنوان یک متغیر خارج از محدوده closure داخلی، مورد استفاده قرار گرفت.

مثالی از Closure در array_walk:

<?php
// Set a multiplier

$multiplier = 3;

// Create a list of numbers
$numbers = array(1,2,3,4);

// Use array_walk to iterate

// through the list and multiply

array_walk($numbers, function($number) use($multiplier) {

  echo $number * $multiplier;

});
در مثال بالا تقریبا این نیاز احساس نمی‌شود که یک تابع بسازید که 2 عدد را در هم ضرب کند در حالی که فقط در یک جا مورد استفاده قرار میگیرد. با استفاده از یک Closure به عنوان callback، ما می‌توانیم تابع را یکبار استفاده کنیم و دیگر آن را فراموش کنیم.

استفاده از this$ در توابع ناشناخته

در نیمه اول سال 2012، یعنی زمانی که PHP به نسخه 5.4 خودش رسید، قابلیت جدیدی به توابع ناشناخته اضافه شد. بوسیله این قابلیت قادر هستید به راحتی با استفاده از this$ داخل تابع ناشناخته، به یک نمونه Object دسترسی داشته باشید.

<?php
class Foo
{

  function hello() {
    echo 'Hello Nettuts!';
  }

  function anonymous()
  {
    return function() {
      $this->hello(); // $this wasn't possible before
    };
  }

}

class Bar
{

  function __construct(Foo $Foo) // object of class Foo typehint
  {
    $x = $Foo->anonymous(); // get Foo::hello()

    $x(); // execute Foo::hello()
  }

}

new Bar(new Foo); // Hello Nettuts!

استفاده در دنیای واقعی

یک مثال معروف از استفاده از این نوع توابع در routing درخواست ها در فریم ورک های مدرن است.

به عنوان مثال Laravel، به شما اجازه میده که مثل زیر عمل کنید:

<?php
Route::get('user/(:any)', function($name) {
  return "Hello " . $name;
});
کد بالا به سادگی با URLایی مثل user/Philip/، تطبیق داده می‌شود.

این یک مثال خیلی ساده بود، اما روشن میکند که چطور یک Closure در شرایطی که به آن نیاز هست می‌تواند مورد استفاده واقع شود.

بدون دیدگاه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *