สรุปสั้น

  • เปิด declare(strict_types=1); และใส่ type ให้ parameter กับค่าที่ return
  • เปรียบเทียบด้วย === เหมือน JavaScript
  • array ของ PHP เป็นทั้ง list และ key-value ในตัวเดียว
  • ความปลอดภัย 3 ข้อที่ห้ามพลาด: prepared statement กัน SQL injection, htmlspecialchars กัน XSS, password_hash เก็บรหัสผ่าน
  • คำสั่งฐานข้อมูลดูต่อที่ พื้นฐาน SQL

1. โครงไฟล์และตัวแปร

<?php
declare(strict_types=1);   // บังคับชนิดข้อมูลให้ตรง ลดบั๊กแปลงชนิดเอง
 
$name = "Somchai";         // ตัวแปรขึ้นต้นด้วย $
$age = 30;
$price = 99.5;
$isActive = true;
$nothing = null;
 
echo "สวัสดี {$name} อายุ {$age}";   // string แบบ " แทรกตัวแปรได้
echo 'ไม่แทรก $name';                // string แบบ ' ไม่แทรก

ไฟล์ที่มีแต่ PHP ไม่ต้องปิดด้วย ?> ช่วยกันช่องว่างหลุดออกไปใน output

2. การเปรียบเทียบ

0 == "a"      // false ใน PHP 8 (PHP 7 เป็น true!)
"1" == "01"   // true   ← แปลงเป็นตัวเลขก่อนเทียบ
"1" === "01"  // false

ใช้ === และ !== เสมอ ฟังก์ชันอย่าง in_array และ array_search ให้ส่ง true เป็นพารามิเตอร์ตัวที่ 3 เพื่อเทียบแบบเข้มงวด

$city = $user['address']['city'] ?? 'ไม่ระบุ';   // null coalescing: ไม่มี key ก็ไม่ error
$zip  = $order?->customer?->zip;                 // nullsafe (PHP 8)

3. Array

$fruits = ["apple", "banana"];                 // แบบ list (index 0, 1, ...)
$user = ["name" => "Somchai", "age" => 30];    // แบบ key => value
 
$fruits[] = "mango";                           // เพิ่มท้าย
foreach ($user as $key => $value) {
    echo "$key: $value\n";
}

ฟังก์ชันที่ใช้บ่อย:

array_map(fn($p) => $p * 1.07, $prices);         // แปลงทุกตัว
array_filter($prices, fn($p) => $p > 90);        // กรอง (key เดิมยังอยู่!)
array_values(array_filter(...));                 // เรียง key ใหม่ 0, 1, 2
array_sum($prices);
in_array("apple", $fruits, true);
array_key_exists("name", $user);
count($fruits);

array_filter ไม่รีเซ็ต key

ผลลัพธ์อาจเป็น [0 => ..., 2 => ...] พอแปลงเป็น JSON จะกลายเป็น object แทน array ครอบด้วย array_values() ก่อนส่งออก

4. ฟังก์ชันและ type

function calcVat(float $amount, float $rate = 0.07): float
{
    return round($amount * $rate, 2);
}
 
function findUser(int $id): ?User      // ? = อาจคืน null
{
    // ...
}
 
$double = fn(int $x): int => $x * 2;   // arrow function (PHP 7.4+)

match: แทน switch ที่ปลอดภัยกว่า

$label = match ($status) {
    'paid'      => 'ชำระแล้ว',
    'pending'   => 'รอชำระ',
    default     => 'ไม่ทราบสถานะ',
};

match เทียบแบบ === คืนค่าได้ และถ้าไม่มีกรณีไหนตรงเลย (และไม่มี default) จะ throw error แทนที่จะเงียบ

5. OOP

namespace App\Services;
 
interface PaymentGateway
{
    public function charge(int $amountSatang): bool;
}
 
final class OrderService
{
    public function __construct(
        private readonly PaymentGateway $gateway,   // constructor promotion (PHP 8)
    ) {}
 
    public function checkout(Order $order): void
    {
        if (! $this->gateway->charge($order->totalSatang)) {
            throw new PaymentFailedException("ชำระเงินไม่สำเร็จ");
        }
    }
}
  • interface กำหนดว่า “ต้องมี method อะไร” ทำให้สลับตัวจริงหรือ mock ตอนเทสต์ได้
  • constructor injection ส่งของที่ต้องใช้เข้ามาทาง constructor แทนการ new เองข้างใน
  • enum (PHP 8.1) ใช้แทนค่าคงที่แบบ string
enum OrderStatus: string {
    case Paid = 'paid';
    case Pending = 'pending';
}
OrderStatus::from('paid');   // OrderStatus::Paid

6. Composer และ autoload

composer require guzzlehttp/guzzle

Composer จัดการ library และโหลด class ให้อัตโนมัติตามชื่อ namespace (มาตรฐาน PSR-4) แค่ require 'vendor/autoload.php'; ครั้งเดียว

7. Error และ Exception

try {
    $service->checkout($order);
} catch (PaymentFailedException $e) {
    // จัดการเฉพาะกรณีที่รู้วิธีแก้
} finally {
    // ทำเสมอ เช่น ปิด connection
}

อย่า catch (Exception $e) {} แล้วปล่อยว่าง ความผิดพลาดจะหายไปเงียบ ๆ และหาสาเหตุไม่เจอ

8. ความปลอดภัยที่ต้องทำทุกครั้ง

SQL injection → ใช้ prepared statement

// ❌ อันตราย: ผู้ใช้พิมพ์ ' OR 1=1 -- ก็ดึงข้อมูลได้ทั้งตาราง
$pdo->query("SELECT * FROM users WHERE email = '$email'");
 
// ✅ ปลอดภัย
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");
$stmt->execute(['email' => $email]);
$user = $stmt->fetch();

XSS → escape ก่อนแสดงผล

echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');

รหัสผ่าน → hash เสมอ

$hash = password_hash($password, PASSWORD_DEFAULT);
if (password_verify($input, $hash)) { /* ถูกต้อง */ }

ห้ามเก็บรหัสผ่านตรง ๆ และห้ามใช้ md5 หรือ sha1

จุดที่มักพลาด

  • ใช้ == แล้วเจอการแปลงชนิดแปลก ๆ
  • empty("0") เป็น true → ถ้าต้องการเช็กว่ามีค่าไหม ใช้ isset หรือเทียบตรง ๆ
  • ลืมว่า PHP 7 กับ 8 มีพฤติกรรมต่างกันบางจุด (เช่นการเทียบ string กับตัวเลข) → เช็กเวอร์ชันของ server ก่อน
  • ใช้ float กับเงิน → เก็บเป็นสตางค์ (int) หรือใช้ library ทศนิยม
  • query ใน loop (ปัญหา N+1) → ดูวิธีแก้ใน พื้นฐาน SQL

แหล่งอ้างอิง