Jan
2
2011

Bài 7 – Câu lệnh điều kiện rút gọn, câu lệnh điều kiện phức hợp & câu lệnh rẽ nhánh

(Bài học lên mạng ngày 2/1/2011) Ở bài này, chúng ta sẽ cùng nghiên cứu cấu trúc rút gọn của câu lệnh điều kiện IF, câu lệnh điều kiện phức hợp (ELSEIF) và câu lệnh rẽ nhánh SWITCH.

Câu lệnh điều kiện rút gọn

Quay lại với ví dụ “ông Ac-xi-met” ở bài 6, chúng ta sẽ sử dụng câu lệnh điều kiện:

<?php

echo 'Ban co the cho ong Ac-xi-met 1 diem tua khong? (C/K): ';
$co1diemtua = trim(fgets(fopen('php://stdin','r')));

if( $co1diemtua == 'c' || $co1diemtua == 'C' )
{
	echo 'Ong Ac-xi-met se nhac bong duoc trai dat len!';
}
else
{
	echo 'Ong Ac-xi-met KHONG THE nhac bong duoc trai dat len.';
}

echo "\n\n";

?>

Tuy nhiên, PHP cung cấp cho chúng ta một cách viết code ngắn hơn bằng việc sử dụng cấu trúc rút gọn của lệnh IF như sau:

<?php

echo 'Ban co the cho ong Ac-xi-met 1 diem tua khong? (C/K): ';
$co1diemtua = trim(fgets(fopen('php://stdin','r')));

/*
if( $co1diemtua == 'c' || $co1diemtua == 'C' )
{
	echo 'Ong Ac-xi-met se nhac bong duoc trai dat len!';
}
else
{
	echo 'Ong Ac-xi-met KHONG THE nhac bong duoc trai dat len.';
}
*/

//echo 'Ong Ac-xi-met',

echo 	'Ong Ac-xi-met ',
		($co1diemtua == 'c' || $co1diemtua == 'C') ? 'co the': 'KHONG THE',
		' nhac bong duoc trai dat len!';

echo 	'Ong Ac-xi-met ',
		'co the',
		' nhac bong duoc trai dat len!';

echo "\n---\n\n";

?>

Kết quả chạy chương trình vẫn cho ta một kết quả đúng:

Có thể cách viết lệnh echo ở đây khiến các bạn thấy hơi lạ, tuy nhiên, nếu phân tích kỹ thì nó chỉ là cấu trúc đã được học mà thôi. Sở dĩ tôi nhảy cách xuống dòng sau mỗi dấu phẩy là để cho các bạn dễ theo dõi. Chúng ta thử gom nhóm các thành phần của nó lại như sau:

Dữ liệu mà chúng ta nhờ echo xuất ra màn hình gồm 3 vế, phân cách nhau bởi dấu , (dấu phẩy). Vế 1 gạch chân đỏ và vế 3 gạch chân xanh nước biêtn chỉ là những đoạn text thuần tuý. Vế 2 gạch chân xanh lá cây là một câu lệnh IF rút gọn, nó được diễn dịch ra thành “ Nếu biến $co1diemtua bằng c (c nhỏ) hoặc C (C lớn) thì trả về giá trị ‘co the’, nếu không thì trả về giá trị ‘KHONG THE’ “.

Như vậy, khi chạy chương trình, với dữ liệu người dùng nhập vào là c hoặc C, câu lệnh echo của chúng ta sẽ tương đương với:

Còn nếu giá trị nhập vào là K, k hay khong the, abc… gì đó thì câu lệnh echo sẽ tương đương với:

Tóm lại, cấu trúc của lệnh IF rút gọn là:

( biểu-thức-điều-kiện ) ? giá-trị-khi-BTDK-đúng : giá-trị-khi-BTĐK-sai ;

Chính vì câu lệnh điều kiện rút gọn thường để trả về giá trị khi đúng, giá trị khi sai (giá trị thay vì câu lệnh) nên lập trình viên thường sử dụng nó “đính kèm” trong phép gán hoặc lệnh echo luôn cho tiện.

Ví dụ để so sánh 2 số, với câu lệnh điều kiện đầy đủ, chúng ta sẽ viết thế này:

if($a>$b) echo ‘A > B’; else echo ‘A <= B’;

Còn với lệnh điều kiện rút gọn, chúng ta sẽ viết echo lên trước:

echo ‘A’,  ($a>$b) ?  ‘ > ’ : ‘ <= ’ , ‘B’;

Kết quả chạy chương trình:

Các bạn có thể xem ví dụ trong file 7.3-so-lon-nhat.php, thay đổi các giá trị biến $a, $b và chạy thử.

Tuy nhiên, nếu bài toán không yêu cầu tìm số lớn hơn mà tìm số lớn nhất, thì chúng ta sẽ thay đổi câu lệnh echo như thế này:

echo ‘Số lớn nhất là: ’,  ($a>$b) ? ‘A’ : ‘B’;

Kết quả khi chạy chương trình với $a=1$b=2 như sau:

Nhưng nếu $a = 1$b = 1 thì chương trình lại có “lỗi” về logic:

Để sửa lại, chúng ta có thể dùng câu lệnh điều gọn rút gọn lồng nhau thế này:

<?php

$a = 1; $b = 1;

echo 	'A = ',$a,'; B = ',$b,'; Ket luan: ',
		'So lon nhat la: ', ($a>$b) ? 'A' : (($a==$b) ? 'KHONG CO SO LON NHAT VI A=B' : 'B');

?>

Tất nhiên khi này kết quả nhìn ra không được đẹp lắm với dòng chữ “số lớn nhất là không có số lớn nhất”. Hơn nữa, bản thân việc rút gọn là để cho… gọn, thế thì việc lại phức tạp cái gọn đó lên là “không hay ho” lắm nên chúng ta chỉ phân tích rõ với nhau để hiểu vấn đề còn trong thực tế, việc sử dụng thế nào là do mỗi người tự quyết định.

Câu lệnh điều kiện phức hợp ELSEIF

Ngoài cấu trúc IF(…) ELSE … thông dụng, PHP còn cung cấp cho chúng ta câu lệnh điều kiện phức hợp bằng cách sử dụng từ khoá elseif khá tiện như sau:

if($a==1) $en = ‘One’;
elseif($a==2) $en = ‘Two’;
elseif($a==3) $en = ‘Three’;
else $en=‘Em be moi hoc dem tu mot den ba’;

Nó tương đương với:

if($a>=1 && $a<=3)
{
    if($a==1) $en = ‘One’;
    if($a==2) $en = ‘Two’;
    if($a==3) $en = ‘Three’;
}
else
{
    $en=‘Em be moi hoc dem tu mot den ba’;
}

Hoặc cũng tương đương với:

if($a==1) $en = ‘One’;
else
{
    if($a==2) $en = ‘Two’;
    else
    {
        if($a==3)
            $en = ‘Three’;
        else
            $en=‘Em be moi hoc dem tu mot den ba’;
    }
}

Tất nhiên, nhìn vào ví dụ sẽ thấy ngay sự tiện dụng của elseif không chỉ vì nó ngắn gọn hơn mà còn vì nó làm cho code của chúng ta được “mạch lạc” và gần với “ngôn ngữ tự nhiên” hơn. Trong khi else được hiểu là “nếu không thì” thì elseif có thể hiểu là “hoặc nếu”.

if($a==1) $en = ‘One’;
elseif($a==2) $en = ‘Two;
elseif($a==3) $en = ‘Three’;
else $en=’Em be moi hoc dem tu mot den ba’;
Nếu a=1 thì en=One
Hoặc nếu a=2 thì en=Two
Hoặc nếu a=3 thì en=Three
Nếu không thì en=Chưa được học

Câu lệnh rẽ nhánh switch

Nếu elseif giúp cho mã nguồn của chúng ta có vẻ mạch lạc hơn thì switch sẽ giúp sự mạch lạc đó nâng cao hơn một mức. Vì câu lệnh điều liện giúp chúng ta xem xét một biểu thức điều kiện là đúng hay sai (a có lớn hơn b không chẳng hạn) nên khi xét một điều kiện xảy ra nhiều trường hợp thì chúng ta phải gia tăng câu lệnh If lồng nhau (hoặc dùng elseif), ví dụ như bài tập xét giá trị của biến $day và ghi ra nghĩa tiếng Anh tương ứng, $day phải xét 8 giá trị khác nhau và một tập các giá trị ngoài vùng từ 2 đến 8.

Hay như bài tập 6.10 ghi ra chữ tiếng Anh của số trong khoảng từ 1-30, chúng ta phải xét đến 30 trường hợp khác nhau của biến (hoặc “khéo léo” lắm thì cũng là 4-5 trường hợp).

Câu lệnh switch được sinh ra để giải quyết những bài toán xét các trường hợp khác nhau của một biến như chúng ta đề cập. Hãy xem ví dụ dưới đây:

<?php

echo 'Day la robot dich so Viet - Anh. Hay nhap mot so bat ki: ';

$n = (int)trim(fgets(fopen('php://stdin','r')));

switch($n)
{
	case 0	: echo 'zero'; break;
	case 1	: echo 'one'; break;
	case 2	: echo 'two'; break;
	case 3	: echo 'three'; break;
	default	: echo 'Robot chua duoc hoc chu nay, robot chi doc duoc tu 0-3';
}

echo "\n\n";

?>

Kết quả khi chạy chương trình:

Cách sử dụng lệnh rẽ nhánh switch như sau:

switch( biến hoặc biểu thức)
{
case trường-hợp-1: tập-lệnh-1; break;
case trường-hợp-2: tập-lệnh-2; break;

case trường-hợp-n: tập-lệnh-n; break;
default: tập-lệnh-cho-các-trường-hợp-khác-không-rơi-vào-các-trường-hợp-đã-liệt-kê;
}

Mặc dù đây là cách sử dụng “mẫu mực” của một câu lệnh switch nhưng chỉ những chữ màu đỏ là bắt buộc. Còn phần màu cam là tuỳ chọn. Do PHP sẽ thực thi lần lượt – rẽ vào các nhánh – của câu lệnh switch từ trên xuống dưới nên từ khoá break đặt ra ở cuối tập lệnh giúp PHP nhảy thẳng ra khỏi câu lệnh switch. Nếu không, PHP sẽ so sánh < biến hoặc biểu thức > để tìm ra < trường hợp > nào đó mà nó thấy đúng đầu tiên, sau đó thực thi tập cả các tập lệnh còn lại . Tức là giá trị sau case chỉ đóng vai trò điều hướng lối rẽ đầu tiên cho trình thông dịch.

Giả sử như trong ví dụ 7.5, nếu chúng ta không thêm vào từ khoá break thì kết quả sẽ bị “chập” thế này:

Chu trình thực thi lệnh của PHP cho trường hợp chúng ta nhập vào số 2 được mô tả qua hình dưới đây:

Đó là lý do đừng quên từ khoá break để yêu cầu PHP thoát khỏi câu lệnh rẽ nhánh ngay lập tức, sau khi rẽ vào một nhánh nào đó đầu tiên.

Một ứng dụng tiêu biểu của switch là để viết một chương trình có sử dụng menu như ví dụ 7.6 dưới đây:

<?php

echo "\n\n";
echo 'Nhap so thu nhat, A = '; $a = (float)trim(fgets(fopen('php://stdin','r')));
echo 'Nhap so thu hai, B = '; $b = (float)trim(fgets(fopen('php://stdin','r')));

echo '

+------------------------+
| 1: Tinh tong 2 so (+)  |
| 2: Tinh hieu 2 so (-)  |
| 3: Tinh tich 2 so (x)  |
| 4: Tinh thuong 2 so (/)|
+------------------------+
| 0: Ket thuc            |
+------------------------+

Hay chon: ';

$c = (int)trim(fgets(fopen('php://stdin','r')));

switch($c)
{
	case 1:
	{
		echo 'Tinh tong 2 so, ',$a,' + ',$b,' = ',($a+$b);
		break;
	}
	//---------------------------------------------
	case 2:
	{
		break;
	}
	//---------------------------------------------
	case 3:
	{
		break;
	}
	//---------------------------------------------
	case 4:
	{
		break;
	}
	//---------------------------------------------
	default	: echo 'Xin chao. Bye bye...'; break;
}

?>

Cặp dấu ngoặc nhọn được thêm vào sau case để giúp chúng ta “bao” các khối lệnh lại nhìn cho dễ. Cũng như các ký tự “gạch gạch” là để phân tách các trường hợp ra với nhau cũng là thủ thuật giúp lập trình viên viết code “thoáng đoãng” mà thôi chứ không phải là các quy định bắt buộc gì.

Sau khi chạy thử chương trình và thấy không có lỗi. Lập trình viên chỉ cần “bôi đen” toàn bộ code từ trên xuống dưới, gõ TAG một cái để đẩy code dịch về bên phải (cho đẹp) rồi chèn thêm vòng lặp do-while vô như ví dụ ở đoạn video dưới đây thì chương trình đã gần như trở nên “hoàn mĩ”.

Hoặc xem tại YOUTUBE

Menu sẽ hiện ra cho người dùng chọn, chương trình thực hiện và menu lại hiện ra chờ lệnh tiếp theo. Chỉ khi nào người dùng nhập vào giá trị 0 (rỗng) thì chương trình mới thoát ra ngoài. Do chúng ta chưa học về vòng lặp nên tôi không đi sâu phân tích, tuy nhiên các bạn có thể nhìn video và làm theo để thử.

Bài tập:

Bài 7.1. Trong ví dụ 7.5, nếu ta nhập vào chữ MOT khi được hỏi thì chương trình sẽ in ra màn hình giá trị thế nào? Tại sao?

Bài 7.2. Hãy hoàn chỉnh ví dụ 7.6 để chương trình thực hiện được các tính năng 2,3,4 còn thiếu.

Bài 7.3. Hãy viết chương trình thực hiện các công việc sau: nhập 3 số bất kì. Tạo menu cho người dùng chọn thực thi một trong các tính năng sau:

  1. Kiểm tra xem 3 số đó có phải là số đo 3 cạnh của một tam giác hay không?
  2. Tìm số lớn nhất.
  3. Xét xem 3 số đó có phải số nguyên tố hay không?
  4. Xét xem 3 số đó theo thứ tự nhập vào (a,b rồi c chẳng hạn) có tạo ra được thành một ngày tương ứng a/b/c (d/m/y) hay không? Giả sử nhập vào 1, 2, 3 thì sẽ có ngày 1, tháng 2, năm 3 là hợp lệ; giả sử nhập vào 34, 1, 2010 thì không hợp lệ vì không có ngày 34/1/2010…
  5. Xét xem tổng của 3 số này là số chẵn hay số lẻ?
  6. Nếu 3 số đó theo thứ tự nhập vào tạo thành ngày tháng năm sinh của người sử dụng thì nói cho họ biết tính đến năm nay họ đã sống được bao nhiêu ngày tuổi?
  7. Nếu 3 số đó theo thứ tự nhập vào tạo thành ngày tháng năm sinh của người sử dụng thì nói cho họ biết tính đến năm nay họ đã sống qua được bao nhiêu năm nhuận?
  8. Nếu 3 số đó theo thứ tự nhập vào tạo thành ngày tháng năm sinh của người sử dụng thì nói cho họ biết tuổi của họ tính theo can chi sẽ là gì? (Giáp, Ất, Bính, Đinh, Mậu, Kỷ, Canh, Tân, Nhâm, Quí / Tý, Sửu, Dần, Mão, Thìn, Tỵ, Ngọ, Mùi, Thân, Dậu, Tuất, Hợi)

Các bạn tuỳ ý dùng if, else, elseif và switch theo sở thích!

Các bạn xem và thảo luận các vấn đề liên quan đến bài học này tại topic: http://nguyenngoclong.com/forum/index.php/topic,33.msg365.html

Các ví dụ trong bài học: Bai_7.zip

Tất cả các học viên làm đầy đủ bài tập 7 đều có quà lì xì của lớp học. Chúc các bạn học tốt, một năm mới nhiều niềm vui, may mắn, hạnh phúc và… enjoy PHP party ^^

Bài tập yêu cầu nộp trước 12h đêm thứ 4, 05/01/2011.

About the Author:

Leave a comment