عملگرهای مقایسه‌ای برای خلاصه نویسی در PHP

ترجمه و تالیف : فاطمه شیرزادفر
تاریخ انتشار : 15 مهر 99
خواندن در 4 دقیقه
دسته بندی ها : پی اچ پی

احتمالاً از قبل با بعضی‌ از عملگرهای مقایسه‌ای در php آشنا هستید. چیزهایی مثل عملگر سه‌تایی یا سه‌گانه?: ، null coalescing ?? و اپراتور spaceship <=>. اما آیا واقعاً می‌دانید که این‌ها چگونه کار می‌کنند؟ دانستن اینکه این عملگرها چه هستند و چه‌ می‌کنند، باعث می‌شود تا از آن‌ها بیشتر استفاده کنید و در نتیجه کد تمیزتری داشته باشید.

قبل از این که نگاهی عمیق‌تر به هر یک از این عملگرها داشته باشیم، خلاصه‌ای از کارهایی که هر کدام از این عملگرها انجام می‌دهند را برای شما در زیر شرح می‌دهم:

  • از عملگر سه‌تایی یا سه‌گانه برای کوتاه کردن ساختار if/else استفاده می‌شود.
  • برای ارائه مقادیر پیش‌فرض به جایnull، از  عملگر null coalescing استفاده می‌شود.
  • از عملگر spaceship برای مقایسه‌ی دومقدار استفاده می‌شود. 

عملگر سه‌تایی

اپراتور سه‌گانه یا همان سه‌تایی برای کوتاه ساختن ساختار  if {} else {} استفاده می‌شود. در‌واقع به جای نوشتن این:

if ($condition) {
    $result = 'foo' 
} else {
    $result = 'bar'
}

می‌توانید این را بنویسید:

$result = $condition ? 'foo' : 'bar';

اگر این $condition درست یا true باشد، مقدار سمت چپی در عملگر(عملوند سمت چپ) به $result اختصاص پیدا می‌کند و اگر شرط false باشد، مقدار سمت راستی در عملگر (عملوند سمت راست) استفاده می‌شود.

چند واقعیت جالب : در‌واقع نام عملگر سه‌گانه به معنای «اپراتوری است که روی سه عملوند، عمل می‌کند». Operand یا عملوند اصطلاحی است که برای مشخص کردن قسمت‌های مورد نیاز از یک عبارت به‌کار می‌رود. عملگر سه‌تایی تنها عملگر در php است که به سه عملوند نیاز دارد:شرط یا condition، نتیجه true و false. به همین ترتیب،عملگرهای binary و unary نیز وجود دارند؛ در اینجا می‌توانید اطلاعات بیشتری درباره آن‌ها بدست آورید.

برگردیم به عملگر سه‌تایی: آیا می‌دانید کدام یک از عبارت‌ها را true ارزیابی می‌کند، و کدام را نه؟ نگاهی به ستون بولین این جدول بیندازید.

هنگامی که ارزیابی شرط true باشد، عملوند سمت چپی استفاده می‌شود. این می‌تواند یک string ، یک عدد صحیح(integer) یا بولین و … باشد. از عملوند سمت راستی برای مقادیر false استفاده می‌شود.

مثال‌های آن عبارتند از 0 یا ’0’ ، یک آرایه خالی یا رشته، null، یک متغییر تعریف نشده یا unassigned (معین نشده)، و البته که مقدار false. تمام این مقادیر باعث می‌شود تا عملگر سه‌تایی از عملوند سمت راستی خود استفاده کند.

خلاصه‌نویسی عملگر سه‌تایی

از آن‌جا که از php ۵.۳ استفاده می‌شود، می‌توان عملوند سمت چپ را ننوشت که عبارت کوتاه‌تری را ارائه می دهد:

$result = $initial ?: 'default';

در این حالت، مقدار $result، مقدار $initial خواهد بود، مگر اینکه $initial نادرست یا false باشد که در این حالت از رشته 'default' استفاده خواهد شد.

شما می‌توانید این عبارت را با همان روش معمول اپراتور سه‌تایی بنویسید:

$result = $condition ? $condition : 'default';

از قضا، با کنار گذاشتن عملوند دوم در عملگر سه‌تایی، در واقع به یک عملگر باینری تبدیل می‌شود.

زنجیرکردن عملگر سه‌تایی

موارد زیر گرچه منطقی به‌نظر می‌رسد ولی در php کار نمی‌کند:

$result = $firstCondition
    ? 'truth'
    : $elseCondition
        ? 'elseTrue'
        : 'elseFalse';

دلیل این امر این است که عملگر سه‌تایی در php «شرکت پذیری چپ» دارد؛ بنابراین این به روشی بسیار عجیب ترجمه (parse) می‌شود. در مثال بالا ابتدا قسمت $elseCondition ارزیابی می‌شود، پس حتی اگر $firstCondition درست یا true هم باشد شما هرگز خروجی آن را نمی‌بینید.

به طور کلی من متعقدم که کار درست این است که از عملگرهای سه تایی تو در تو اجتناب کنید. می‌توانید درباره این رفتار عجیبب و غریب درStack Overflow ، بخش پاسخ‌ها بیشتر بخوانید.

علاوه بر این، در php ۷.۴، استفاده از عملگرهای سه‌تایی زنجیروار و بدون براکت‌ها را چیز بدی می‌دانند.

عملگر Null coalescing

آیا قبلاً به جدول مقایسه type ها نگاه کردید؟ عملگر null coalescing از php۷.۰ در دسترس قرار گرفته. این عملگر شبیه به عملگر سه‌تایی است؛ اما مثل isset در عملوند سمت چپ رفتار می‌کند، به جای اینکه فقط از مقدار بولین استفاده کند. این امر باعث می‌شود این عملگر خصوصا برای آرایه‌ها و assign کردن مقادیر پیش‌فرض هنگامی که متغییری تنظیم نشده باشد، مفید باشد.

$undefined ?? 'fallback'; // 'fallback'

$unassigned;
$unassigned ?? 'fallback'; // 'fallback'

$assigned = 'foo';
$assigned ?? 'fallback'; // 'foo'

'' ?? 'fallback'; // ''
'foo' ?? 'fallback'; // 'foo'
'0' ?? 'fallback'; // '0'
0 ?? 'fallback'; // 0
false ?? 'fallback'; // false

عملگر null coalescing دو عملوند می‌گیرد و آن را به یک عملگر باینری تبدیل می‌کند. در ضمن، "Coalescing" به معنای "جمع شدن برای تشکیل توده یا یکی شدن یک چیز ". این دو عملوند خواهد گرفت و تصمیم می‌گیرد که کدام یک از آن‌ها را بر اساس مقدار عملوند سمت چپی استفاده کنید.

Null coalescing در آرایه‌ها

این عملگر به خاطر دارا بودن رفتار و عملکردی مثل isset، به‌خصوص در ترکیب شدن با آرایه‌ها بسیار مفید است. این به این معنیست که شما به سرعت می‌توانید وجود keyها، حتی key های تو در تو را بدون نوشتن عبارات طولانی، بررسی کنید.

$input = [
    'key' => 'key',
    'nested' => [
        'key' => true
    ]
];

$input['key'] ?? 'fallback'; // 'key'
$input['nested']['key'] ?? 'fallback'; // true
$input['undefined'] ?? 'fallback'; // 'fallback'
$input['nested']['undefined'] ?? 'fallback'; // 'fallback'

null ?? 'fallback'; // 'fallback'

مثال اول را می‌توان با استفاده از یک عملگر سه‌تایی نیز نوشت :

$output = isset($input['key']) ? $input['key'] : 'fallback';

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

// Returns `true` instead of the value of `$input['key']`
$output = isset($input['key']) ?: 'fallback' 

// The following will trigger an 'undefined index' notice 
// when $output is no array or has no 'key'.
//
// It will trigger an 'undefined variable' notice 
// when $output doesn't exist.
$output = $input['key'] ?: 'fallback';

زنجیر کردن عملگر Null coalesce

عملگر null coalescing به راحتی می‌تواند زنجیر (chain) شود:

$input = [
    'key' => 'key',
];

$input['undefined'] ?? $input['key'] ?? 'fallback'; // 'key'

coalescing تو در تو

حتی اگر یک property در chain تهی یا null باشد، این ممکن است که عملگر null coalescing در object propertie های تو در تو مورد استفاده قرار بگیرد.

$a = (object) [
    'prop' => null,
];

var_dump($a->prop->b ?? 'empty');

// 'empty'

عملگر Null coalescing assignment

در php۷.۴، می‌توانیم انتظار یک سینتکس کوتاه‌تر به نام "null coalescing assignment operator" را داشته باشیم.

// This operator will be available in PHP 7.4

function (array $parameters = []) {
    $parameters['property'] ??= 'default';
}

در این مثال، $parameters['property'] پیش‌فرض یا 'default' تنظیم خواهد شد، مگر اینکه در آرایه‌ای که به فانکشن pass می‌شود، ست شده باشد. استفاده از عملگر null coalescing فعلی، برابر با موارد زیر خواهد بود :

function (array $parameters = []) {
    $parameters['property'] = $parameters['property'] ?? 'default';
}

عملگر Spaceship

اگرچه عملگر Spaceship نام کاملاً خاصی دارد، اما می‌تواند بسیار هم مفید باشد. این عملگری است که برای مقایسه استفاده می‌شود و همیشه یکی از این سه مقدار را برمی‌گرداند:0 , 1- یا 1.

0 وقتی return می‌شود که مقدار هر دو عملوند برابر باشند، 1 هنگامی که عملوند سمت چپ بزرگ‌تر باشد و 1- در صورتی که عملوند سمت راست بزرگ‌تر است. بیایید به این مثال ساده نگاهی بیندازیم:

1 <=> 2; // Will return -1, as 2 is larger than 1.

در این مثال ساده همه‌ چیز وجود ندارد، درسته؟ با این حال عملگر spaceship می‌تواند خیلی بیشتر از چند مقدار ساده را مقایسه کند!

// It can compare strings,
'a' <=> 'z'; // -1

// and arrays,
[2, 1] <=> [2, 1]; // 0

// nested arrays,
[[1, 2], [2, 2]] <=> [[1, 2], [1, 2]]; // 1

// and even casing.
'Z' <=> 'z'; // -1

به طور عجیبی، هنگام مقایسه بزرگ و کوچک بودن حروف،‌ حروف کوچک بالاتر در نظر گرفته می‌شود. هر چند که یک مثال ساده وجود دارد؛ مقایسه رشته یا مقایسه کاراکتر به ازای هر کاراکتر انجام می‌شود. به محض اینکه یک کاراکتر متفاوت باشد، مقدار ASCII آن‌ها مقایسه می‌شود؛ و از آن‌جا که در جدول ASCII، حروف کوچک بعد از حروف بزرگ می‌آیند، ارزش آن‌ها بالاتر است.

مقایسه اشیاء(Object)

عملگر spaceship تقریباً می‌تواند هر چیزی، حتی اشیاء را باهم مقایسه کند.نحوه مقایسه اشیاء هم بر اساس نوع آن‌ها است کلاس‌های داخلی php می‌توانند مقایسه خود را تعیین کنند، درحالی که userland object ها (اشیاء مبتنی بر کاربر) بر اساس attribute ها و مقدارشان مقایسه می‌شوند.

چه زمانی می‌خواهید آبجکتی که می‌خواهید را مقایسه کنید؟ خب، یک مثال بسیار واضح وجود دارد: زمان‌ها.

$dateA = DateTime::createFromFormat('Y-m-d', '2000-02-01');

$dateB = DateTime::createFromFormat('Y-m-d', '2000-01-01');

$dateA <=> $dateB; // Returns 1

البته مقایسه زمان‌ها فقط یکی از نمونه‌هاست، اما با وجود این یک مثال بسیار مفید است. 

فانکشن‌ها را مرتب کنید

یکی از کاربرد‌های بسیار خوب این عملگر، مرتب‌سازی آٰرایه هاست. چندین روش برای مرتب کردن آٰرایه در php وجود دارد، و بعضی از این متدها به کاربر اجازه تعریف یک فانکشن مرتب ‌سازی را می‌دهد.

این فانکشن باید دو المنت را مقایسه کند و بر اساس موقعیت آن‌ها 0،1 یا 1- را برگرداند.

یک مورد عالی برای عملگر spaceship !

$array = [5, 1, 6, 3];

usort($array, function ($a, $b) {
    return $a <=> $b;
});

// $array = [1, 3, 5, 6];

برای مرتب‌سازی به صورت نزولی، می‌توانید نتیجه‌ی مقایسه را معکوس کنید:

usort($array, function ($a, $b) {
    return -($a <=> $b);
});

// $array = [6, 5, 3, 1];

امیدوارم این مقاله از راکت به شما کمک کرده باشد و برای شما مفید باشد، از وقتی که برای خواندن گذاشتید ممنونم!

منبع

گردآوری و تالیف فاطمه شیرزادفر
آفلاین
user-avatar

تجربه کلمه‌ای هست که همه برای توصیف اشتباهاتشون ازش استفاده میکنن، و من همیشه دنبال اشتباهات جدیدم! برنامه‌نویس هستم و لینوکس‌ دوست

دیدگاه‌ها و پرسش‌ها

برای ارسال نظر لازم است ابتدا وارد سایت شوید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید