💻 آخرین فرصت یادگیری برنامه‌نویسی با آفر ویژه قبل از افزایش قیمت در ۵ آذر ماه (🎁 به همراه یک هدیه ارزشمند )
۰ ثانیه
۰ دقیقه
۰ ساعت
۰ محسن موحد
معرفی عملگرها - قسمت دوم (مقاله)
جامعه پی اچ پی ایجاد شده در ۰۳ دی ۱۳۹۸

در مقاله ی قبل، در مورد عملگرهای ریاضی، انتساب و مقایسه ای صحبت کردیم و برای هر کدام مثال‌های متنوعی آوردیم تا با جزئیات این عملگرها آشنا شوید.
در این جلسه میخواهیم مابقی عملگرهای PHP را معرفی کنیم.

عملگر کنترل خطا: (Error Control Operator)
زبان PHP از یک عملگر برای کنترل خطا، پشتیبانی میکند. این عملگر @ میباشد.
یه وقت هست که نمیدونید عبارتی که نوشتید، خطا واسش اتفاق میفته یا نه (یا حتی میدانید که خطا اتفاق می‌افتد) و یا اینکه این احتمال رو میدید که شاید در جریان پردازش، برای یک عبارت(مثل باز کردن یک فایل یا استارت کردن سشن و ...) خطایی رخ دهد و اگر خطایی رخ داد، نمیخواهید در صفحه ی نمایش کاربر، آن خطا نمایش داده شود، میتوانید قبل از آن عبارت، عملگر @ را بیاورید. عملگر @ باعث عدم نمایش آن خطا میشود.(یعنی عملاً خطای آن عبارت، در حالت سکوت قرار میگیرد.)
به مثال زیر توجه کنید:

<?php
echo $bidak; // Notice: Undefined variable: bidak
echo @$bidak;

خط 2: چون $bidak تعریف نشده است، خطای Notice رخ میدهد.
خط 4: اما در این خط، با گذاشتن عملگر @ قبل از عبارت، خطا را نادیده میگیرد و چیزی در صفحه چاپ نخواهد کرد.
البته این فقط یک مثال بود و معمولاً کسی در این مورد از این عملگر استفاده نمیکند چون توابعی مانند isset() و empty() برای چک کردن یک متغیر وجود دارد و نیازی نیست که در این مورد، روی خطا سرپوش بگذاریم.

این عملگر هر خطای تولید شده از آن عبارت، از قبیل (Notice ، Warning ، Fatal  و ...) را در حالت سکوت قرار میدهد.
به یک مثال دیگر توجه کنید:

<?php
echo $i / 0;
// Notice: Undefined variable: i
// Warning: Division by zero

مثال بالا، دو خطا نمایش میدهد. اولین خطا یک Notice است که اطلاع میدهد، متغیر $i وجود ندارد.
دومین خطا یک Warning است که هشدار میده داریم تقسیم بر صفر انجام میدیم.
حالا میخواهم با عملگر @ جلوی این دو خطا را بگیرم:

<?php
echo @$i / 0;
// Warning: Division by zero

با اجرای کد بالا، خواهید دید که خطای Notice حذف شده است ولی خطای Warning هنوز هست.
برای اینکه از خطای کل عبارت تقسیم جلوگیری کنید، میبایست عبارت تقسیم را داخل پرانتز بگذارید و @ را قبل از پرانتز:

<?php
echo @($i / 0);

حالا دیگر خطایی چاپ نخواهد شد.
با توجه به مثال بالا، ابتدا تقسیم انجام میشود و بعد عملگر @ روی حاصل تقسیم، سرپوش میگذارد. علت اینکه عبارت داخل پرانتز، اول اجرا میشود به اولویت عملگرها مربوطط میشود که در جلسه ی بعدی، به اولویت عملگرها خواهیم پرداخت. ولی همنقدر بدانید که عبارات داخل پرانتز دارای بالاترین اولویت اجرا میباشد.
از این لینک میتوانید، ترتیب اولویت عملگرها را ببینید.

توجه داشته باشید که در مثال قبل، نمیتوانید @ را قبل از echo بنویسید:

<?php
@echo $i / 0;
// Parse error: syntax error, unexpected 'echo'

میبینید که خطا اتفاق می‌افتد و اسکریپت اجرا نخواهد شد.

نکته: میتوانید از این عملگر، قبل از متغیرها، توابع، متدها، اینلکودها، ثابت‌ها و ... استفاده کنید. اما نمیتوانید این عملگر را قبل از عبارت تعاریف تابع و کلاس یا ساختارهای شرطی مانند @if ، @foreach و ... بیاورید.

چند مورد از موارد مجاز را ببینید:

<?php
$file = @fopen('file1', 'a');
//------------------------------//
if($a = @fopen('file1', 'r'))
	echo "File1 was opened.";
//------------------------------//
$value = @$cache[$key];
//------------------------------//
@session_start();

توجه: اگر تابعی شخصی برای مدیریت خطا با set_error_handler() نوشته اید، برای اینکه بتوانید از @ هم در برنامه هایتان استفاده کنید، میبایست داخل تابع، چک کنید که آیا error_reporting() فعال است یا خیر و اگر فعال بود، آن خطا، نمایش داده شود. بخاطر اینکه، وقتی از عملگر @ استفاده میکنید، error_reporting بصورت موقت، غیر فعال میشود و وقتی تابعی برای مدیریت خطاها مینویسید، اگر چک نکرده باشید که این مورد فعال است یا خیر، عملگر @ کار نخواهد کرد و در هر صورت خطا چاپ میشود.
نکته: error_reporting در فایل تنظیمات php.ini وجود دارد.
در مباحث جلوتر در مورد خطاهای PHP و مدیریت آنها بصورت مفصل، صحبت خواهیم کرد.

توصیه: حتی المقدور، از عملگر @ در برنامه هایتان استفاده نکنید. به علت اینکه اینکار بیشتر سرپوش گذاشتن روی یک عیب است و حتی گاهی اوقات به علت نمایش ندادن خطایی، شما عیب برنامه را پیدا نمیکنید. پس بهترین کار، حل آن عیب است.

نکته: همچنین عملگر @ پرفورمنس برنامه را پایین میآورد.
برای مثال opcode‌های دستور echo $i / 0; را ببینید:

line     #        op             return  operands
---------------------------------------------------
   2     0        DIV            ~0      !0, 0
         1        ECHO                   ~0
         2        RETURN                 1

لازم نیست متوجه این دستورات شوید. فقط به تعداد دستورات نگاه کنید: #0 و #1 و #2
اما حالا opcode‌های دستور echo @($i / 0) را ببینید:

line     #        op                    return  operands
-----------------------------------------------------------
   2     0        BEGIN_SILENCE         ~0      
         1        FETCH_R               $1      'i'
         2        DIV                   ~2      $1, 0
         3        END_SILENCE                   ~0
         4        ECHO                          ~2
         5        RETURN                        1

میبینید که عملگر @ سه دستورالعمل نسبت به کد قبلی، بیشتر دارد.(3 دستور اضافه شده مربوط به عملگر @ میباشد.)
+ ( در مقاله ی بررسی تاریخچه زبان PHP، کمی در مورد opcode‌ها هم صحیت کرده ایم.)

توجه: عملگر @ فقط از نمایش خطا در درون صفحه، جلوگیری میکند و ارتباطی با توقف یا عدم توقف اسکریپت ندارد.
توقف اسکریپت بستگی به نوع خطا دارد، برای مثال اگر خطای گرامری داشته باشید، برنامه کامپایل نخواهد شد، در نتیجه دیگر عملگر @ معنی نمیدهد چون برنامه اجرا نشده است. اما اگر خطای گرامری نداشته باشید و برنامه کامپایل شود و یک خطا از نوع Fatal Error اتفاق بیفتد، با توجه به وجود عملگر @ آن خطا نمایش داده نمیشود ولی اسکریپت، متوقف میشود. اما برای مثال اگر خطا از نوع Noticed باشد، آن خطا نمایش داده نمیشود و اسکریپت ادامه پیدا میکند.

 

* عملگرهای بیتی: (Bitwise Operators)
همانطورکه از نامشان پیداست، این عملگرها روی بیت ها کار میکنند.
ابتدا لیست زیر را ببینید، تا بدانیم، عملگرهای بیتی کدام‌ها هستند:

Example    |    Name
------------------------------
$a & $b	        And	
$a | $b	        Or 
$a ^ $b	        Xor 
~ $a	        Not	
$a << $b	    Shift left
$a >> $b	    Shift right

حالا این 6 عملگر را یکی یکی معرفی میکنیم:
+ عملگر & : (نامش And است و فقط روی بیت‌ها کار میکند.)
این عملگر روی بیت‌های متناظر دو عملوند کار میکند.
برای مثال اگر دو عدد 5 و 0 داشته باشیم، این دو عدد در مبنای باینری، به شکل زیر در میآیند:

5 = 0000 0101
0 = 0000 0000

هر یک از بیت‌های عملوند اول، با بیت متناظر خود در عملوند دوم، در نظر گرفته میشود.
توجه: در عملگر & اگر هر دو بیت متناظر، برابر 1 باشند(true باشند)، نتیجه 1(true) خواهد بود و در غیر اینصورت نتیجه 0(false) میباشد.
حالا اگر 5 & 0 را انجام دهیم، به شکل زیر در میآید:

5 = 0000 0101
  &
0 = 0000 0000
--------------
0 = 0000 0000

میبینید که حاصل 5 & 0 برابر با 0000 0000 شده است، و این عدد بدست آمده، در مبنای 10 برابر است با همان 0.
در مثال زیر، چند عدد دیگر را باهم & میکنیم:

1 = 0001
  & 
5 = 0101
---------
1 = 0001
//------------------------------//
2 = 0010
  &
5 = 0101
---------
0 = 0000
//------------------------------//
4 = 0100
  &
5 = 0101
---------
4 = 0100
//------------------------------//
8 = 1000
  &
5 = 0101
---------
0 = 0000

تفاوت نمیکند داده ی شما از چه نوعی باشد، در مثال زیر دو string را باهم & میکنیم:

m = 01101101
  &
o = 01101111 
-------------
m = 01101101
//------------------------------//
m = 01101101
  &
w = 01110111
-------------
e = 01100101

حالا که با & آشنا شدیم، چند نمونه مثال در PHP اجرا میکنیم:

<?php
var_dump(5 & 0); // 0
var_dump(5 & 1); // 1
var_dump(5555 & 2222); // 162
var_dump(5 & 'bidak'); // 0
var_dump(true & false); // 0
var_dump(true & true); // 0
var_dump(null & false); // 0
var_dump('m' & 'w'); // e

نکته: اگر در عمل & هر دو عملوند، string باشند، حاصل & یک string از اندینگ ASCII میباشد و در بقیه ی موارد(از قبیل یک string و یک integer و ...) به هر دو عملوند به integer تبدیل میشوند. (میتوانید برای بررسی این نکته، مثال قبلی را مجدداً نگاه کنید.)
توجه: این نکته شامل عملگرهای | و ^ هم میشود. (در ادامه آین دو عملگر را هم معرفی خواهیم کرد.)

میخواهیم یک شرط بصورت ترکیبی از عملگر مقایسه ای و عملگر بیتی بنویسیم:

<?php
$a = 5;
$b = 'bidak';
var_dump($a & $b == true); // 1
/*
($a & ($b == true)) =>
(5 & ('bidak' == true)) =>
(5 & (true == true)) =>
(5 & true) =>
(5 & 1) =>
(0101 & 0001) =>
(0001) => 
(1)
*/
//------------------------------//
var_dump($a & ($b == true)); // 1
/*
($a & ($b == true)) =>
(5 & ('bidak' == true)) =>
(5 & (true == true)) =>
(5 & true) =>
(5 & 1) =>
(0101 & 0001) =>
(0001) =>
(1)
*/
var_dump(($a & $b) == true); // false
/*
(($a & $b) == true) =>
((5 & 'bidak') == true) =>
((5 & 0) == true) =>
((0101 & 0000) == true) =>
(0 == true) =>
(false == true) =>
(false)
*/

3 مثال آورده شده که زیر هر مثال، توضیحات علت نتیجه بصورت comment آمده است. اما اولی را توضیح میدهم.
خط 2 var_dump($a & $b == true); // 1 : با توجه به اینکه اولویت عملگر == بالاتر از عملگر & میباشد، ابتدا دو عملوند کنار == اجرا خواهند شد. این عبارت مثل اینستت که بنویسید $a & ($b == true) و چون پرانتز دارای بالاترین اولویت است، بنابراین ابتدا، عبارت داخل پرانتز اجرا میشود.
متغیر $b یک string با مقدار 'bidak' است که با یک مقدار boolean مقایسه میشود. در مقاله ی قبل گفتیم که در مقایسه ی بین هر نوع عبارتی با boolean، آن عبارت همم تبدیل به boolean میشود. بنابراین آنچیزی که مقایسه میشود true == true است که نتیجه برابر true خواهد بود.
حالا که نتیجه ی true بدست آمده، نوبت عملگر & است. پس عبارت $a & true را داریم.
متغیر $a یک integer با مقدار 5 است و در نکات بالا گفتیم، دو عملوند از هر نوعی(بجز دو string) به integer تبدیل میشوند.
بنابراین true به 1 تبدیل میشود و داریم 5 & 1 در نتیجه جمع باینری این دو عدد برابر 11 خواهد شد.

 

+ عملگر  | : (نامش Or است و فقط روی بیت‌ها کار میکند.)
در این عملگر، اگر حداقل بک بیت متناظر برابر 1 باشد، نتیجه 1 است و در غیر اینصورت، اگر جفت بیتها 0 بودند، نتیجه 0 خواهد بود.(حداقل یک بیت 1 باشد.)

0 = 0000
  | 
5 = 0101
---------
5 = 0101
//------------------------------//
1 = 0001
  | 
5 = 0101
---------
5 = 0101
//------------------------------//
2 = 0010
  |
5 = 0101
---------
7 = 0111

 

+ عملگر ^ : (نامش Xor است و فقط روی بیت‌ها کار میکند.)
اگر دو بیت متناظر، یک بیت 0 و دیگری 1 بود، نتیجه 1 خواهد بود وگرنه اگر دو بیت متناظر، یکی باشند(یعنی جفتشان 0 یا جفتشان 1) نتیجه 0 خواهد بود.
منظور اینه که بین دو bit متناظر، یا اولی 1 باشه، یا دومی و جفتشون مثل هم نباشه.

0 = 0000
  ^ 
5 = 0101
---------
5 = 0101
//------------------------------//
1 = 0001
  ^ 
5 = 0101
---------
4 = 0100
//------------------------------//
2 = 0010
  ^
5 = 0101
---------
7 = 0111

 

+ عملگر ~ : (نامش Not است و فقط روی بیت‌ها کار میکند.)
این عملگر، نقیض یک bit است. یعنی اگر یک bit برابر 0 باشد، نقیضش 1 میشود و برعکس.
برای مثال ~ 0 = 15 خواهد بود. به مثال‌های زیر توجه کنید: 

~ 0  = 0000
------------
  15 = 1111
//------------------------------//
~ 5  = 0101
-----------
  10 = 1010
//------------------------------//
~ 7 = 0111
-----------
  8 = 1000

 

+ عملگر << : (نامش Shift Left است و فقط روی بیت‌ها کار میکند.)
این عملگر، به تعداد بیتی که به آن میدهیم، عملوند اول را به سمت چپ، شیفت میدهد.
عبارت 5 << 2 را در نظر بگیرید، مقدار باینری عدد 5 (یعنی 0101) باید 2 بیت به سمت چپ شیفت کند(0 1 0 1 - -). برای شیفت دادن به سمت چپ، 2 بیت با مقدار 0 به طرف راست عدد 5 اضافه میشود، پس حاصل برابر است با 0 1 0 1 0 0 .
به مثال زیر توجه کنید:

5 = 0101
------------------------
5 << 1 = 0101 0    = 10
5 << 2 = 0101 00   = 20
5 << 3 = 0101 000  = 40
5 << 4 = 0101 0000 = 80

 

+ عملگر >> : (نامش Shift Right است و فقط روی بیت‌ها کار میکند.)
این عملگر، به تعداد بیتی که به آن میدهیم، عملوند اول را به سمت راست، شیفت میدهد.
عبارت 5 << 2 را در نظر بگیرید، مقدار باینری عدد 5 (یعنی 0101) باید 2 بیت به سمت راست شیفت کند(0 1). میبینید برای شیفت دادن به سمت راست، به تعداد 2بیت از بیت‌های سمت راست خود را از دست داده است.

15 = 1111
------------------------
15 >> 1 =  0111  = 7
15 >> 2 =  0011  = 3
15 >> 3 =  0001  = 1
15 >> 4 =  0000  = 0

نکته: نوع هر دو عملوند در عملگرهای <<  و >> به integer تبدیل میشوند.(البته اگر integer نباشند.)

نکته: موارد استفاده از عملگرهای بیتی به خودتان بستگی دارد که در مواجهه با هر مسئله از چه الگوریتمی بهره ببرید. ممکن است از عملگرهای بیتی هیچ استفاده ای نکنید یا اینکه در مواجهه با هر مسئله، بهترین الگوریتم را پیاده کنید. بستگی به شما دارد که در روابط بین بیت ها، دنبال چه عدد و رقمی برای حل مسئله ی خود هستید. مثلا میتوانید در ترکیب رنگ‌ها یا چک کردن پرمیشن‌های یک کاربر، الگوریتمی طراحی کنید که از قابلیت عملگرهای بیتی بهره ببرید. در قسمت‌های جلوتر، جلسه ای مخصوص روش‌های حل مسئله، مطرح میکنیم تا ذهنتان خط بگیرد.

 

عملگرهای بیتی به پایان رسیده است. حالا میخواهیم عملگرهای منطقی را معرفی کنیم.
* عملگرهای منطقی: (Logical Operators)
عملگرهای منطقی از لحاظ اسمی، شبیه به عملگرهای بیتی هستند امــا عملکرد متفاوتی با یکدیگر دارند و ما در شروطی که در برنامه هایمان مینویسیم، اکثرا از این عملگرهای منطقی استفاده میکنیم.
عملکرد: خروجی این عملگرها یا true است یا false ، بنابراین این عملگرها روی نتایج عملوندهای خود کار میکنند.
برای مثال true && true یا false and false و ... (false و true خودش ممکن است، نتیجه ی یک عبارت شرطی دیگر باشد.)
همچنین عملگرهای منطقی اصطلاحاً short-circuit هستند. برای مثال در شرط false && true اگر شرط اول برقرار نباشد دیگر شرط دوم بررسی نمیشود.

برای شرح این موضوع، ابتدا لیست عملگرهای زیر را ببینید:

Example    |    Name
------------------------------
$a and $b	    And	
$a or $b	    Or	
$a xor $b	    Xor	
! $a	        Not	
$a && $b	    And
$a || $b	    Or

 

+ عملگر and :
اگر دو طرف and برابر true باشند، نتیجه true خواهد بود، در غیر اینصورت، نتیجه false است.
برای مثال $a and $b اگر $a == true (یعنی $a != false) باشد و همچنین $b == true (یعنی $b != false) باشد، نتیجه ی and برابر true خواهد بود.

نکته: همانطور که گفتیم، در  عملگر and اگر نتیجه ی عملوند اول true نباشد، دیگر عملوند دوم، چک نخواهد شد و جواب and برابر false خواهد بود. (اما در عملگرهای بیتی اینطور نیست و دو عملوند بررسی میشود. چون باید دو عملوند بیت هایشان با هم & یا | یا ^ شوند و در پایان عملیات بیتی است که نتیجه معلوم میشود.)

<?php
var_dump(true and true); // true
//------------------------------//
var_dump(true and false); // false
//------------------------------//
var_dump(false and false); // false
//------------------------------//
var_dump(2 and true); // true and true => true
//------------------------------//
var_dump('false' and true); // true and true => true
//------------------------------//
var_dump('0' && null); // false and false => false
//------------------------------//
var_dump('0.0' and null); // true and false => false
//------------------------------//
var_dump([] and '-1'); // false and true => false
//------------------------------//
var_dump([1, 2] and 0.1); // true and true => true

 

+ عملگر && :
مانند عملگر and است و تفاوتش فقط در اولویت است. عملگر && اولویت بالاتری نسبت به عملگر and دارد.

<?php
var_dump(true && true); // true
//------------------------------//
var_dump(true && false); // false
//------------------------------//
var_dump(false && false); // false
//------------------------------//
var_dump(2 && true); // true && true => true
//------------------------------//
var_dump('false' && true); // true && true => true
//------------------------------//
var_dump('0' && null); // false && false => false
//------------------------------//
var_dump('0.0' && null); // true && false => false
//------------------------------//
var_dump([] && '-1'); // false && true => false
//------------------------------//
var_dump([1, 2] && 0.1); // true && true => true

 

+ عملگر or :
کافیست یک عملوند برابر true باشد تا نتیجه true شود.

نکته: اگر عملوند اول true باشد، دیگر عملوند دوم چک نمیشود و جواب or برابر true خواهد بود.

<?php
var_dump(true or true); // true
//------------------------------//
var_dump(true or false); // true
//------------------------------//
var_dump(false or false); // false
//------------------------------//
var_dump(2 or true); // true or true => true
//------------------------------//
var_dump('false' or true); // true or true => true
//------------------------------//
var_dump('0' or null); // false or false => false
//------------------------------//
var_dump('0.0' or null); // true or false => true
//------------------------------//
var_dump([] or '-1'); // false or true => true
//------------------------------//
var_dump([1, 2] or 0.1); // true or true => true

 

+ عملگر || :
مانند عملگر or است و تفاوتش فقط در اولویت است. عملگر || دارای اولویت بالاتری نسبت به عملگر or میباشد.

 

+ عملگر xor:
باید یک عملوند true و عملوند دیگر false باشد تا نتیجه ی xor برابر true باشد. در غیر اینصورت اگر هر دو عملوند false یا هر دو عملوند true باشند، نتیجه ی xor برابر fasle خواهد بود.

<?php
var_dump(true xor true); // false
//------------------------------//
var_dump(false xor false); // false
//------------------------------//
var_dump(2 xor true); // true xor true => false
//------------------------------//
var_dump(true xor false); // true

 

+ عملگر ! : (NOT)
نقیض یک مقدار است. اگر عملوند true باشد، نتیجه false است و اگر عملوند false باشد نتیجه true خواهد بود.

<?php
var_dump(!true); // false
//------------------------------//
var_dump(!false); // true
//------------------------------//
var_dump(!(true || false)); // !(true) => false
//------------------------------//
var_dump(!(true and false)); // !(false) => true

خط 6 و 8: با گذاشتن پرانتز، یک گروه(بسته) را مشخص کرده ایم و در نتیجه عملگر ! روی نتیجه ی داخل پرانتز، عمل خواهد کرد.

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