วัน: 8 มกราคม 2023

PHP: ให้ปลอดภัยและไร้บั๊กด้วย Strict TypesPHP: ให้ปลอดภัยและไร้บั๊กด้วย Strict Types

สำหรับนักพัฒนาที่คุ้นเคยกับภาษา PHP มานาน คงทราบดีว่า PHP เป็นภาษาประเภท Dynamically Typed Language หรือภาษาที่เราไม่ต้องกำหนดชนิดข้อมูลให้ตัวแปรอย่างเข้มงวด มันสามารถแปลงร่างจาก String เป็น Integer หรือจาก Boolean เป็น String ได้โดยอัตโนมัติ (Type Coercion)

ความยืดหยุ่นนี้ดูเหมือนจะดี… จนกระทั่งระบบของคุณเริ่มใหญ่ขึ้น และเกิดบั๊กแปลก ๆ ที่หาตัวยากขึ้นเรื่อย ๆ

บทความนี้จะพาทุกคนไปรู้จักกับ Strict Types ฟีเจอร์ที่จะช่วยเปลี่ยนให้ PHP ของคุณทำงานด้วยระบบจัดการชนิดข้อมูลที่เข้มงวด แม่นยำ และปลอดภัยเหมือนภาษารุ่นใหญ่อย่าง Java หรือ C# ครับ


ปัญหาของ PHP ยุคเก่า: เมื่อ “10” เท่ากับ 10

ลองดูตัวอย่างฟังก์ชันคำนวณภาษีแบบปกติใน PHP (Default Mode)

<?php
function calculateTax(int $price, int $taxRate) {
    return $price * ($taxRate / 100);
}

// เรียกใช้งานฟังก์ชัน
echo calculateTax(100, "7");

ในโหมดปกติ โค้ดนี้จะรันผ่านฉลุยและได้ผลลัพธ์เป็น 7 ทั้งๆ ที่เราส่ง String "7" เข้าไป เพราะ PHP จะใจดีแอบแปลงชนิดข้อมูลให้เราที่หลังบ้าน (Implicit Type Coercion)

ทำไมสิ่งนี้ถึงอันตราย? ถ้าหากข้อมูลที่ส่งเข้ามาไม่ใช่ "7" แต่เกิดความผิดพลาดจากระบบอื่นกลายเป็น "7 percent" หรือส่งค่า true เข้ามา PHP ก็จะพยายามแปลงค่าเหล่านั้นให้ทำงานต่อได้อยู่ดี ซึ่งอาจทำให้ผลลัพธ์การคำนวณเพี้ยนไปโดยที่ระบบไม่มีการแจ้งเตือน Error ใด ๆ เลย


ทางออกคือการเปิดใช้งาน Strict Types

ตั้งแต่ PHP 7.0 เป็นต้นมา (ที่ไม่เคยใช้กันจริง ๆ ) เราสามารถสั่งให้ PHP เปิดระบบตรวจข้อมูลอย่างเข้มงวดได้ โดยการใส่คำสั่งนี้ไว้ที่ บรรทัดแรกสุด ของไฟล์

declare(strict_types=1);

เมื่อใส่คำสั่งนี้แล้ว PHP จะเปลี่ยนพฤติกรรมทันที หากมีการส่งข้อมูลผิดประเภท ตัวจำลองการทำงานจะพ่น TypeError และหยุดทำงาน เพื่อให้เราแก้ไขโค้ดให้ถูกต้องก่อนนำไปใช้งานจริง

<?php
declare(strict_types=1); // เปิดระบบ Strict Mode

function calculateTax(int $price, int $taxRate) {
    return $price * ($taxRate / 100);
}

// เรียกใช้งานฟังก์ชัน
echo calculateTax(100, "7"); 

// ผลลัพธ์: ❌ Fatal error: Uncaught TypeError: calculateTax(): Argument #2 ($taxRate) must be of type int, string given

ความจริง 3 ข้อที่ควรรู้เกี่ยวกับ Strict Types ใน PHP

  1. มีผลเฉพาะไฟล์ (Per-file Basis)
    เราไม่สามารถเปิดตั้งค่า Strict Types แบบครอบจักรวาลใน php.ini ได้ ทีมพัฒนา PHP ออกแบบมาให้คุณต้องใส่ declare(strict_types=1); แยกทีละไฟล์ เพื่อป้องกันไม่ให้ไปกระทบกับ Library เก่า ๆ (Legacy Code) ที่ไม่ได้เขียนรองรับระบบนี้ไว้
  2. ส่งผลทั้งขาเข้า (Argument) และขาออก (Return Type)
    Strict Types ไม่ได้ตรวจเฉพาะตัวแปรที่ส่งเข้าฟังก์ชันเท่านั้น แต่ยังตรวจค่าที่ฟังก์ชันส่งกลับออกมาด้วย (Return Type)
    <?php
    declare(strict_types=1);
    
    function getAge(): int {
        return "25"; // ❌ พังทันที เพราะกำหนดไว้ว่าจะคืนค่าเป็น int แต่ดันส่ง string ออกไป
    }
    
  3. ข้อยกเว้นเดียว: ขยายจาก Int เป็น Float ได้
    ในระบบ Strict Types ของ PHP มีกฎยืดหยุ่นข้อเดียวคือ คุณสามารถส่งค่า int เข้าไปในช่องที่ต้องการ float ได้ เนื่องจากไม่มีการสูญเสียความแม่นยำของข้อมูล (Widening Primitive Conversion) แต่ในทางกลับกัน ส่ง float เข้าไปในช่อง int ไม่ได้ นะครับ
    <?php
    declare(strict_types=1);
    
    function formatPrice(float $number) {
        return number_format($number, 2);
    }
    
    echo formatPrice(150); //  ผ่าน! (PHP ยอมให้แปลง 150 เป็น 150.0 ได้)
    

ฟีเจอร์ร่วมสมัยใน PHP 8.x

ปัจจุบันใน PHP 8 ได้พัฒนาเรื่อง Type System ไปไกลมาก ทำให้การเปิด Strict Types มีความยืดหยุ่นและตอบโจทย์การทำงานจริงมากขึ้น เช่น

  • Union Types: กำหนดให้ตัวแปรรับได้มากกว่า 1 ชนิด เช่น int|float
  • Mixed Type: หากตัวแปรนั้นจำเป็นต้องรับค่าอะไรก็ได้จริงๆ สามารถระบุเป็น mixed ได้
  • Property Types: สามารถกำหนดชนิดข้อมูลให้ตัวแปรภายใน Class (Properties) ได้โดยตรง
<?php
declare(strict_types=1);

class Product {
    // กำหนด Type ให้ Property โดยตรง
    public string $name;
    public int|float $price; // รับได้ทั้ง int และ float

    public function __construct(string $name, int|float $price) {
        $this->name = $name;
        $this->price = $price;
    }
}

สรุป: ทำไมเราถึงควรเขียน Strict Types ในวันนี้?

  1. ลดบั๊กได้มหาศาล: บั๊กที่เกิดจากการแปลงชนิดข้อมูลผิดพลาดจะถูกดักจับได้ตั้งแต่ตอนเขียนโค้ด ไม่หลุดไปถึงหน้าโปรดักชัน
  2. โค้ดอ่านง่ายและเป็นเอกสารในตัวเอง: เพื่อนร่วมทีม (หรือแม้แต่ตัวเราในอนาคต) มาอ่านโค้ด จะเข้าใจทันทีว่าฟังก์ชันนี้ต้องการค่าอะไร และจะได้อะไรกลับไป
  3. IDE ทำงานได้ฉลาดขึ้น: โปรแกรมอย่าง VS Code หรือ PHPStorm จะช่วยแจ้งเตือนและเติมโค้ด (Autocompletion) ให้เราได้อย่างแม่นยำ 100%

คำแนะนำ: หากคุณกำลังเริ่มต้นโปรเจกต์ใหม่ในยุคนี้ แนะนำให้ใส่ declare(strict_types=1); ไว้ที่หัวไฟล์ของทุกไฟล์ (หรือตั้งค่าใน Editor ให้เจนให้อัตโนมัติ) เพื่อคุณภาพโค้ดที่ยอดเยี่ยมในระยะยาวครับ!


อ่านเพิ่มเติม