สำหรับนักพัฒนาที่คุ้นเคยกับภาษา 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
- มีผลเฉพาะไฟล์ (Per-file Basis)
เราไม่สามารถเปิดตั้งค่า Strict Types แบบครอบจักรวาลในphp.iniได้ ทีมพัฒนา PHP ออกแบบมาให้คุณต้องใส่declare(strict_types=1);แยกทีละไฟล์ เพื่อป้องกันไม่ให้ไปกระทบกับ Library เก่า ๆ (Legacy Code) ที่ไม่ได้เขียนรองรับระบบนี้ไว้ - ส่งผลทั้งขาเข้า (Argument) และขาออก (Return Type)
Strict Types ไม่ได้ตรวจเฉพาะตัวแปรที่ส่งเข้าฟังก์ชันเท่านั้น แต่ยังตรวจค่าที่ฟังก์ชันส่งกลับออกมาด้วย (Return Type)<?php declare(strict_types=1); function getAge(): int { return "25"; // ❌ พังทันที เพราะกำหนดไว้ว่าจะคืนค่าเป็น int แต่ดันส่ง string ออกไป } - ข้อยกเว้นเดียว: ขยายจาก 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 ในวันนี้?
- ลดบั๊กได้มหาศาล: บั๊กที่เกิดจากการแปลงชนิดข้อมูลผิดพลาดจะถูกดักจับได้ตั้งแต่ตอนเขียนโค้ด ไม่หลุดไปถึงหน้าโปรดักชัน
- โค้ดอ่านง่ายและเป็นเอกสารในตัวเอง: เพื่อนร่วมทีม (หรือแม้แต่ตัวเราในอนาคต) มาอ่านโค้ด จะเข้าใจทันทีว่าฟังก์ชันนี้ต้องการค่าอะไร และจะได้อะไรกลับไป
- IDE ทำงานได้ฉลาดขึ้น: โปรแกรมอย่าง VS Code หรือ PHPStorm จะช่วยแจ้งเตือนและเติมโค้ด (Autocompletion) ให้เราได้อย่างแม่นยำ 100%
คำแนะนำ: หากคุณกำลังเริ่มต้นโปรเจกต์ใหม่ในยุคนี้ แนะนำให้ใส่ declare(strict_types=1); ไว้ที่หัวไฟล์ของทุกไฟล์ (หรือตั้งค่าใน Editor ให้เจนให้อัตโนมัติ) เพื่อคุณภาพโค้ดที่ยอดเยี่ยมในระยะยาวครับ!
อ่านเพิ่มเติม