Skip to content
เข้าสู่ระบบ

Control Flow


Control Flow เป็นโครงสร้างที่ควบคุมทิศทางการทำงานของโปรแกรม ในบทนี้เราจะเรียนรู้การใช้ if/else, switch และ match expressions ใน PHP 8.4+


ใช้ตรวจสอบเงื่อนไขและทำงานตาม:

<?php
$age = 18;
// if พื้นฐาน
if ($age >= 18) {
echo "คุณเป็นผู้ใหญ่แล้ว";
}
// if-else
$score = 75;
if ($score >= 50) {
echo "ผ่าน";
} else {
echo "ไม่ผ่าน";
}
// if-elseif-else
$grade = 85;
if ($grade >= 80) {
echo "เกรด A";
} elseif ($grade >= 70) {
echo "เกรด B";
} elseif ($grade >= 60) {
echo "เกรด C";
} elseif ($grade >= 50) {
echo "เกรด D";
} else {
echo "เกรด F";
}
// Output: เกรด A

Alternative Syntax (สำหรับ templates)

Section titled “Alternative Syntax (สำหรับ templates)”
<?php
$isLoggedIn = true;
?>
<!-- ใช้ใน HTML templates -->
<?php if ($isLoggedIn): ?>
<p>ยินดีต้อนรับ!</p>
<?php else: ?>
<p>กรุณาเข้าสู่ระบบ</p>
<?php endif; ?>
<!-- elseif ก็ได้ -->
<?php if ($role === 'admin'): ?>
<p>คุณเป็น Admin</p>
<?php elseif ($role === 'editor'): ?>
<p>คุณเป็น Editor</p>
<?php else: ?>
<p>คุณเป็น User</p>
<?php endif; ?>
<?php
$age = 25;
$hasLicense = true;
// Nested if
if ($age >= 18) {
if ($hasLicense) {
echo "สามารถขับรถได้";
} else {
echo "ยังไม่มีใบขับขี่";
}
} else {
echo "อายุยังไม่ถึง 18 ปี";
}
// ทำให้ flat ได้ด้วย && (อ่านง่ายกว่า)
if ($age >= 18 && $hasLicense) {
echo "สามารถขับรถได้";
} elseif ($age >= 18) {
echo "ยังไม่มีใบขับขี่";
} else {
echo "อายุยังไม่ถึง 18 ปี";
}
// Early return pattern (แนะนำ)
function canDrive(int $age, bool $hasLicense): string {
if ($age < 18) {
return "อายุยังไม่ถึง 18 ปี";
}
if (!$hasLicense) {
return "ยังไม่มีใบขับขี่";
}
return "สามารถขับรถได้";
}

รูปแบบสั้นของ if-else:

<?php
$age = 20;
// if-else แบบปกติ
if ($age >= 18) {
$status = "ผู้ใหญ่";
} else {
$status = "เด็ก";
}
// Ternary operator
$status = ($age >= 18) ? "ผู้ใหญ่" : "เด็ก";
// Nested ternary (ไม่แนะนำ - อ่านยาก)
$grade = 75;
$result = ($grade >= 80) ? "A" : (($grade >= 60) ? "B" : "F");
// PHP 8.0+: ต้องใส่วงเล็บถ้า nested
// $result = $grade >= 80 ? "A" : $grade >= 60 ? "B" : "F"; // Error!
$result = $grade >= 80 ? "A" : ($grade >= 60 ? "B" : "F"); // OK
// Elvis operator (?:)
$name = "";
$displayName = $name ?: "Guest"; // "Guest" (empty string = falsy)
// Null coalescing (??)
$username = null;
$displayName = $username ?? "Anonymous"; // "Anonymous"
// ต่างกัน:
$value = 0;
echo $value ?: "default"; // "default" (0 เป็น falsy)
echo $value ?? "default"; // 0 (มีค่า ไม่ใช่ null)

ใช้เมื่อมีหลายกรณีที่ต้องตรวจสอบ:

<?php
$day = 3;
switch ($day) {
case 1:
echo "วันจันทร์";
break;
case 2:
echo "วันอังคาร";
break;
case 3:
echo "วันพุธ";
break;
case 4:
echo "วันพฤหัสบดี";
break;
case 5:
echo "วันศุกร์";
break;
case 6:
case 7:
echo "วันหยุด"; // case 6 และ 7 ทำเหมือนกัน
break;
default:
echo "วันไม่ถูกต้อง";
}
// Output: วันพุธ
<?php
$grade = "B";
// ลืม break จะ fall through ไปยัง case ถัดไป
switch ($grade) {
case "A":
echo "ดีเยี่ยม ";
// fall through!
case "B":
echo "ดี ";
// fall through!
case "C":
echo "พอใช้";
break;
default:
echo "ต้องปรับปรุง";
}
// ถ้า $grade = "A": Output: "ดีเยี่ยม ดี พอใช้"
// ถ้า $grade = "B": Output: "ดี พอใช้"
// ถ้า $grade = "C": Output: "พอใช้"
<?php
$color = "red";
switch ($color) {
case "red":
$code = "#FF0000";
break;
case "green":
$code = "#00FF00";
break;
case "blue":
$code = "#0000FF";
break;
default:
$code = "#000000";
}
// Switch ใช้ loose comparison (==)
$value = 0;
switch ($value) {
case "abc": // 0 == "abc" เป็น true! (PHP 7)
echo "matched string"; // อาจ match ผิด
break;
case 0:
echo "matched zero";
break;
}
// PHP 8+: String comparison เป็น false ถ้า compare กับ int
// แต่ก็ควรใช้ match() แทนเพื่อความปลอดภัย
<?php
$color = "blue";
?>
<?php switch ($color): ?>
<?php case "red": ?>
<div style="color: red">Red</div>
<?php break; ?>
<?php case "green": ?>
<div style="color: green">Green</div>
<?php break; ?>
<?php case "blue": ?>
<div style="color: blue">Blue</div>
<?php break; ?>
<?php default: ?>
<div>Unknown color</div>
<?php endswitch; ?>

match เป็น expression ที่ใช้แทน switch ได้ดีกว่าในหลายกรณี:

<?php
$day = 3;
// switch (statement)
switch ($day) {
case 1:
$name = "วันจันทร์";
break;
// ... อีกหลาย case
}
// match (expression) - สั้นกว่า
$name = match($day) {
1 => "วันจันทร์",
2 => "วันอังคาร",
3 => "วันพุธ",
4 => "วันพฤหัสบดี",
5 => "วันศุกร์",
6, 7 => "วันหยุด",
default => "วันไม่ถูกต้อง",
};
echo $name; // "วันพุธ"
Featureswitchmatch
TypeStatementExpression
ComparisonLoose (==)Strict (===)
Fall-throughDefaultไม่มี
Return valueไม่มีมี
Multiple valuesหลาย casecomma separated
Default requiredไม่บังคับError ถ้าไม่ match
<?php
// match ใช้ strict comparison (===)
$value = "1";
$result = match($value) {
1 => "integer one",
"1" => "string one",
default => "other",
};
echo $result; // "string one" (ไม่ใช่ "integer one")
// match returns value
$price = match($membership) {
"gold" => 100,
"silver" => 200,
"bronze" => 300,
default => 500,
};
// match กับ expression
$score = 85;
$grade = match(true) {
$score >= 80 => "A",
$score >= 70 => "B",
$score >= 60 => "C",
$score >= 50 => "D",
default => "F",
};
// match throws error ถ้าไม่ match
$color = "purple";
// match($color) { "red" => 1 }; // UnhandledMatchError!
<?php
$action = "save";
// match สามารถเรียก function ได้
$result = match($action) {
"save" => saveData($data),
"delete" => deleteData($id),
"update" => updateData($id, $data),
default => throw new InvalidArgumentException("Unknown action: $action"),
};
// หรือใช้ callable
$operations = [
"add" => fn($a, $b) => $a + $b,
"subtract" => fn($a, $b) => $a - $b,
"multiply" => fn($a, $b) => $a * $b,
"divide" => fn($a, $b) => $b != 0 ? $a / $b : throw new DivisionByZeroError(),
];
$op = "add";
$result = $operations[$op](10, 5); // 15

รูปแบบพิเศษสำหรับจัดการค่า null:

<?php
// Null coalescing operator (??)
$config = [
"timeout" => 30,
// "retries" ไม่ได้กำหนด
];
$timeout = $config["timeout"] ?? 60; // 30 (มีค่า)
$retries = $config["retries"] ?? 3; // 3 (default)
// Chain ได้
$value = $a ?? $b ?? $c ?? "default";
// Null coalescing assignment (??=) - PHP 7.4+
$array = [];
$array["key"] ??= "default"; // กำหนดเฉพาะถ้าไม่มีหรือ null
echo $array["key"]; // "default"
$array["key"] ??= "new value"; // ไม่เปลี่ยน เพราะมีค่าอยู่แล้ว
echo $array["key"]; // "default"
// Null safe operator (?->) - PHP 8.0+
class User {
public ?Address $address = null;
}
$user = new User();
// วิธีเดิม
$city = null;
if ($user !== null && $user->address !== null) {
$city = $user->address->city;
}
// PHP 8+
$city = $user?->address?->city; // null (ไม่ error)
// ใช้ร่วมกัน
$city = $user?->address?->city ?? "Unknown";

การรวมเงื่อนไขหลายข้อ:

<?php
$age = 25;
$hasLicense = true;
$hasInsurance = false;
// AND - ทุกเงื่อนไขต้องเป็นจริง
if ($age >= 18 && $hasLicense && $hasInsurance) {
echo "สามารถขับรถได้อย่างถูกกฎหมาย";
}
// OR - อย่างน้อยหนึ่งเงื่อนไขเป็นจริง
if ($isAdmin || $isManager || $isOwner) {
echo "มีสิทธิ์เข้าถึง";
}
// NOT - กลับค่า
if (!$isBlocked) {
echo "ผู้ใช้ไม่ถูกบล็อก";
}
// ผสมกัน
if (($age >= 18 && $hasLicense) || $isEmergency) {
echo "อนุญาตให้ขับ";
}
// Short-circuit evaluation
// ถ้าด้านซ้ายของ && เป็น false จะไม่ประเมินด้านขวา
// ถ้าด้านซ้ายของ || เป็น true จะไม่ประเมินด้านขวา
$user = null;
if ($user && $user->isActive()) { // $user->isActive() ไม่ถูกเรียก
echo "User is active";
}
// ใช้ประโยชน์จาก short-circuit
$data = $cache->get("key") || $data = $db->fetch("key");

Pattern ที่ช่วยลด nesting:

<?php
// แบบ nested (อ่านยาก)
function processOrderNested($order) {
if ($order !== null) {
if ($order->isValid()) {
if ($order->isPaid()) {
// process order
return "Order processed!";
} else {
return "Order not paid";
}
} else {
return "Invalid order";
}
} else {
return "No order provided";
}
}
// แบบ guard clauses (อ่านง่าย)
function processOrder($order) {
// Guard clauses - ตรวจสอบเงื่อนไขที่ผิดก่อน
if ($order === null) {
return "No order provided";
}
if (!$order->isValid()) {
return "Invalid order";
}
if (!$order->isPaid()) {
return "Order not paid";
}
// Happy path - ทำงานหลัก
return "Order processed!";
}
// ใช้กับ throw ก็ได้
function divide(float $a, float $b): float {
if ($b === 0.0) {
throw new DivisionByZeroError("Cannot divide by zero");
}
return $a / $b;
}

ค่าที่ถือว่า false ใน PHP:

<?php
// ค่าที่เป็น falsy (ถือว่า false ใน boolean context)
$falsyValues = [
false, // boolean false
0, // integer 0
0.0, // float 0.0
"", // empty string
"0", // string "0"
[], // empty array
null, // null
];
foreach ($falsyValues as $value) {
if (!$value) {
echo gettype($value) . " is falsy\n";
}
}
// ค่าอื่นๆ ทั้งหมดเป็น truthy
$truthyValues = [
true,
1,
-1,
0.1,
"hello",
"false", // string "false" ≠ boolean false
" ", // space
[0], // array with element
new stdClass(),
];
// ระวัง!
if ("0") {
echo "This won't print"; // "0" เป็น falsy!
}
if ("false") {
echo "This WILL print"; // "false" เป็น truthy!
}

แบบฝึกหัดที่ 1: Grade Calculator

Section titled “แบบฝึกหัดที่ 1: Grade Calculator”
<?php
function getGrade(int $score): string {
return match(true) {
$score >= 80 => "A",
$score >= 70 => "B",
$score >= 60 => "C",
$score >= 50 => "D",
default => "F",
};
}
function getGradeMessage(int $score): string {
$grade = getGrade($score);
return match($grade) {
"A" => "ยอดเยี่ยม! คะแนน $score ได้เกรด A",
"B" => "ดีมาก! คะแนน $score ได้เกรด B",
"C" => "ดี! คะแนน $score ได้เกรด C",
"D" => "ผ่าน! คะแนน $score ได้เกรด D",
"F" => "ต้องปรับปรุง คะแนน $score ไม่ผ่าน",
};
}
echo getGradeMessage(85); // "ยอดเยี่ยม! คะแนน 85 ได้เกรด A"
echo getGradeMessage(45); // "ต้องปรับปรุง คะแนน 45 ไม่ผ่าน"

แบบฝึกหัดที่ 2: User Validation

Section titled “แบบฝึกหัดที่ 2: User Validation”
<?php
function validateUser(array $data): array {
$errors = [];
// Guard clauses
if (empty($data["username"])) {
$errors[] = "Username is required";
} elseif (strlen($data["username"]) < 3) {
$errors[] = "Username must be at least 3 characters";
}
if (empty($data["email"])) {
$errors[] = "Email is required";
} elseif (!filter_var($data["email"], FILTER_VALIDATE_EMAIL)) {
$errors[] = "Email is invalid";
}
$password = $data["password"] ?? "";
if (strlen($password) < 8) {
$errors[] = "Password must be at least 8 characters";
}
return $errors;
}
// ทดสอบ
$data = [
"username" => "jo",
"email" => "invalid-email",
"password" => "123",
];
$errors = validateUser($data);
if (!empty($errors)) {
foreach ($errors as $error) {
echo "- $error\n";
}
}

แบบฝึกหัดที่ 3: HTTP Status Handler

Section titled “แบบฝึกหัดที่ 3: HTTP Status Handler”
<?php
function handleHttpStatus(int $code): string {
return match(true) {
$code >= 200 && $code < 300 => "Success: " . match($code) {
200 => "OK",
201 => "Created",
204 => "No Content",
default => "Success",
},
$code >= 300 && $code < 400 => "Redirect: " . match($code) {
301 => "Moved Permanently",
302 => "Found",
304 => "Not Modified",
default => "Redirect",
},
$code >= 400 && $code < 500 => "Client Error: " . match($code) {
400 => "Bad Request",
401 => "Unauthorized",
403 => "Forbidden",
404 => "Not Found",
default => "Client Error",
},
$code >= 500 => "Server Error: " . match($code) {
500 => "Internal Server Error",
502 => "Bad Gateway",
503 => "Service Unavailable",
default => "Server Error",
},
default => "Unknown Status",
};
}
echo handleHttpStatus(200); // "Success: OK"
echo handleHttpStatus(404); // "Client Error: Not Found"
echo handleHttpStatus(500); // "Server Error: Internal Server Error"

1. ใช้ match แทน switch เมื่อทำได้

Section titled “1. ใช้ match แทน switch เมื่อทำได้”
<?php
// ไม่แนะนำ: switch ยาวและต้องจำ break
switch ($status) {
case 'pending':
$label = 'รอดำเนินการ';
break;
case 'processing':
$label = 'กำลังดำเนินการ';
break;
case 'completed':
$label = 'เสร็จสิ้น';
break;
default:
$label = 'ไม่ทราบสถานะ';
}
// แนะนำ: match สั้นและปลอดภัยกว่า
$label = match($status) {
'pending' => 'รอดำเนินการ',
'processing' => 'กำลังดำเนินการ',
'completed' => 'เสร็จสิ้น',
default => 'ไม่ทราบสถานะ',
};
<?php
// ไม่แนะนำ: nested conditions
function process($user, $data) {
if ($user !== null) {
if ($user->isActive()) {
if ($data !== null) {
// ทำงาน
return true;
}
}
}
return false;
}
// แนะนำ: guard clauses
function process($user, $data) {
if ($user === null) return false;
if (!$user->isActive()) return false;
if ($data === null) return false;
// ทำงาน
return true;
}

3. หลีกเลี่ยง Nested Ternary

Section titled “3. หลีกเลี่ยง Nested Ternary”
<?php
// ไม่แนะนำ: nested ternary อ่านยากมาก
$result = $a > $b ? ($c > $d ? 'cd' : 'ab') : ($e > $f ? 'ef' : 'gh');
// แนะนำ: ใช้ match หรือ if-else
$result = match(true) {
$a > $b && $c > $d => 'cd',
$a > $b => 'ab',
$e > $f => 'ef',
default => 'gh',
};

4. ใช้ Null Coalescing อย่างถูกต้อง

Section titled “4. ใช้ Null Coalescing อย่างถูกต้อง”
<?php
// ?? ตรวจสอบ null เท่านั้น
$name = $user['name'] ?? 'Guest';
// ?: ตรวจสอบ falsy value ทั้งหมด
$name = $user['name'] ?: 'Guest';
// ระวัง: 0 และ '' ก็เป็น falsy
$count = 0;
echo $count ?: 'default'; // 'default' (อาจไม่ใช่สิ่งที่ต้องการ)
echo $count ?? 'default'; // 0 (ถูกต้อง)

ปัญหาที่พบบ่อย

Section titled “ปัญหาที่พบบ่อย”
<?php
// ปัญหา: fall-through ที่ไม่ตั้งใจ
$day = 'Mon';
switch ($day) {
case 'Mon':
echo 'Monday'; // ลืม break!
case 'Tue':
echo 'Tuesday';
break;
}
// Output: MondayTuesday
// วิธีแก้: ใช้ match หรืออย่าลืม break
<?php
$value = null;
// อันตราย: loose comparison
if ($value == false) {
// null == false เป็น true!
}
// ปลอดภัย: strict comparison หรือ is_null()
if ($value === null) {
echo 'Value is null';
}
<?php
$status = 'unknown';
// Error! UnhandledMatchError
// $label = match($status) {
// 'active' => 'Active',
// 'inactive' => 'Inactive',
// };
// ควรมี default
$label = match($status) {
'active' => 'Active',
'inactive' => 'Inactive',
default => 'Unknown',
};

ในบทนี้เราได้เรียนรู้:

  • if/else/elseif statements
  • Ternary operator (?:) และ Elvis operator
  • switch statement และ fall-through behavior
  • match expression (PHP 8.0+) และความต่างจาก switch
  • Null coalescing (??) และ null safe operator (?->)
  • Guard clauses pattern
  • Truthiness และ falsiness ใน PHP
  • Best practices สำหรับ control flow

แหล่งข้อมูลเพิ่มเติม

Section titled “แหล่งข้อมูลเพิ่มเติม”

เข้าสู่ระบบเพื่อดูเนื้อหาเต็ม

ยืนยันตัวตนด้วยบัญชี Google เพื่อปลดล็อกบทความทั้งหมด