การมาถึงของ PHP 8.0 ได้เปลี่ยนผ่านฟีเจอร์สำคัญอย่างหนึ่งที่นักพัฒนาเรียกร้องมานาน นั่นคือ Attributes (หรือที่ภาษาอื่นเรียกว่า Annotations) ซึ่งเข้ามาแทนที่การเขียน Docblock Annotations แบบเดิม ๆ ที่เราคุ้นเคยในอดีต เช่น ใน Doctrine ORM หรือ Symfony
บทความนี้จะพาไปดูว่าทำไมเราถึงควรเลิกใช้ Docblocks แล้วหันมาใช้ Attributes แทน พร้อมตัวอย่างการเปรียบเทียบและการนำไปใช้งานจริงครับ
🛑 ปัญหาของ Docblock Annotations แบบเดิม
ที่ผ่านมา PHP ไม่ได้มีระบบ Metadata ติดมากับตัวภาษา ทำให้นักพัฒนาต้องอาศัย PHPDoc คอนเมนต์ (/ ... */) ควบคู่กับ Library ภายนอกเพื่ออ่านคอมเมนต์เหล่านั้นมาตีความ ซึ่งมีข้อเสียหลัก ๆ ดังนี้
- เป็นแค่ String (Plain Text): คอมเมนต์ก็คือคอมเมนต์ ตัว PHP Engine ไม่ได้ช่วยตรวจสอบความถูกต้อง (Syntax Error) ถ้าคุณพิมพ์คำสะกดผิด โปรแกรมจะไม่พังจนกว่าจะรันไปเจอตอนใช้งาน
- พึ่งพาเครื่องมือภายนอก: ต้องใช้โค้ดจำพวก
doctrine/annotationsมาช่วย Parsing คอมเมนต์ออกมาเป็น Object อีกที - มีผลต่อ Performance: การอ่านคอมเมนต์และ Parse สตริงในทุก ๆ Request ส่งผลกระทบต่อความเร็วของระบบ
✨ Attributes คืออะไร?
Attributes คือระบบ Native Metadata ที่ฝังอยู่เป็นส่วนหนึ่งของภาษา PHP (ตั้งแต่ PHP 8.0+) มีหน้าที่ประกาศข้อมูลอธิบายส่วนต่าง ๆ ของโค้ด เช่น Class, Method, Function, Property หรือ Parameter โดยใช้โครงสร้าง #[AttributeName]
ข้อดีของ Attributes
- Native Syntax: ทำงานโดย PHP Core โดยตรง ไม่ต้องพึ่งพา External Parser
- Type Safety & Validation: เนื่องจากมันเป็นโค้ด PHP จริง ๆ ถ้าเราพิมพ์ชื่อ Attribute ผิด หรือส่ง Argument ผิดประเภท ตัว PHP จะแจ้ง Syntax Error หรือ ArgumentCountError ทันที
- Performance ดีกว่า: PHP จัดการคอมไพล์และแคช Attributes ได้ดีกว่าการอ่าน Text คอมเมนต์
🔍 เปรียบเทียบ: Docblocks VS Attributes
ลองมาดูการเปรียบเทียบการสร้าง Route ใน Controller ระหว่างรูปแบบเก่าและรูปแบบใหม่กันครับ
แบบเก่า: Docblock Annotation
use Symfony\Component\Routing\Annotation\Route;
class ProductController
{
/**
* @Route("/product/{id}", name="product_show", methods={"GET"})
*/
public function show(int $id)
{
// ...
}
}
แบบใหม่: PHP Attributes (ตั้งแต่ PHP 8.0+)
use Symfony\Component\Routing\Attribute\Route;
class ProductController
{
#[Route('/product/{id}', name: 'product_show', methods: ['GET'])]
public function show(int $id)
{
// ...
}
}
ข้อสังเกต: ใน Attributes เราสามารถใช้ Named Arguments (name: 'product_show') ของ PHP 8.0 ร่วมด้วยได้ ทำให้โค้ดอ่านง่ายและกระชับขึ้นมาก โดยไม่ต้องใส่ปีกกา {} ซ้อนกันให้วุ่นวายแบบ Docblock
🛠️ วิธีการสร้างและใช้งาน Attributes เอง (Custom Attributes)
เราสามารถสร้าง Attribute ขึ้นมาใช้เองภายในโปรเจกต์ได้ง่าย ๆ ด้วยการประกาศ Class และใส่ Attribute #[Attribute] ไว้บนหัว Class นั้น
Step 1: สร้าง Attribute Class
namespace App\Attributes;
use Attribute;
#[Attribute(Attribute::TARGET_METHOD)] // กำหนดให้ใช้ได้เฉพาะกับ Method เท่านั้น
class RolesAllowed
{
public array $roles;
public function __construct(string ...$roles)
{
$this->roles = $roles;
}
}
Step 2: นำไปใช้งานกับ Method
use App\Attributes\RolesAllowed;
class AdminController
{
#[RolesAllowed('admin', 'superadmin')]
public function deleteUser(int $userId)
{
// โค้ดลบข้อมูลผู้ใช้งาน
}
}
Step 3: การอ่านค่าด้วย Reflection API
การดึงค่าจาก Attribute มาใช้งาน จะใช้ความสามารถของ Reflection API ใน PHP ครับ
$reflectionMethod = new ReflectionMethod(AdminController::class, 'deleteUser');
// ดึง Attributes ทั้งหมดที่ชื่อ RolesAllowed ออกมา
$attributes = $reflectionMethod->getAttributes(RolesAllowed::class);
if (!empty($attributes)) {
// แปลงกลับมาเป็น Instance ของ Class RolesAllowed เพื่อใช้งาน
$rolesAllowedInstance = $attributes[0]->newInstance();
// ดึงข้อมูล Roles ออกมาเช็ค
$allowedRoles = $rolesAllowedInstance->roles;
print_r($allowedRoles); // ผลลัพธ์: ['admin', 'superadmin']
}
📊 ตารางสรุปความแตกต่าง
| คุณสมบัติ | Docblock Annotations | PHP Attributes (PHP 8+) |
| ประเภท | เป็นเพียง “คอมเมนต์” (Text) | เป็น “โครงสร้างภาษา” (Native Code) |
| ความเร็ว (Performance) | ช้ากว่า (ต้องใช้ Regex/Parser) | เร็วกว่า (PHP Core จัดการให้) |
| การตรวจสอบข้อผิดพลาด | ตรวจสอบยาก (IDE อาจไม่เตือน) | ตรวจสอบทันที (Syntax Error / Static Analysis) |
| การพิมพ์คำสั่ง | ใช้ @ นำหน้าคำสั่ง | ใช้ #[ ] ครอบคำสั่ง |
| การจัดรูปแบบข้อมูล | ใช้ JSON-like หรือ Syntax เฉพาะ | ใช้ Array และ Named Arguments ของ PHP ได้เลย |
💡 สรุป
การเปลี่ยนมาใช้ Attributes แทน Docblock Annotations ไม่เพียงแต่ทำให้โค้ดของคุณดูเป็นระเบียบและทันสมัยขึ้น แต่ยังช่วยลดข้อผิดพลาดในระบบ (Human Error) จากการพิมพ์คอมเมนต์ผิด และเพิ่มประสิทธิภาพในการทำงานของแอปพลิเคชันอีกด้วย
หากคุณกำลังขึ้นโปรเจกต์ใหม่ด้วย PHP 8+ หรือกำลังใช้ Framework เวอร์ชันปัจจุบัน แนะนำให้ปรับมาใช้ Attributes เต็มตัวได้เลยครับ!
อ่านเพิ่มเติม