PlusMagi's Blog By Pitt Phunsanit

PHP: การใช้ Attributes แทนการเขียน Docblocks Annotations

การมาถึงของ PHP 8.0 ได้เปลี่ยนผ่านฟีเจอร์สำคัญอย่างหนึ่งที่นักพัฒนาเรียกร้องมานาน นั่นคือ Attributes (หรือที่ภาษาอื่นเรียกว่า Annotations) ซึ่งเข้ามาแทนที่การเขียน Docblock Annotations แบบเดิม ๆ ที่เราคุ้นเคยในอดีต เช่น ใน Doctrine ORM หรือ Symfony

บทความนี้จะพาไปดูว่าทำไมเราถึงควรเลิกใช้ Docblocks แล้วหันมาใช้ Attributes แทน พร้อมตัวอย่างการเปรียบเทียบและการนำไปใช้งานจริงครับ


🛑 ปัญหาของ Docblock Annotations แบบเดิม

ที่ผ่านมา PHP ไม่ได้มีระบบ Metadata ติดมากับตัวภาษา ทำให้นักพัฒนาต้องอาศัย PHPDoc คอนเมนต์ (/ ... */) ควบคู่กับ Library ภายนอกเพื่ออ่านคอมเมนต์เหล่านั้นมาตีความ ซึ่งมีข้อเสียหลัก ๆ ดังนี้


✨ Attributes คืออะไร?

Attributes คือระบบ Native Metadata ที่ฝังอยู่เป็นส่วนหนึ่งของภาษา PHP (ตั้งแต่ PHP 8.0+) มีหน้าที่ประกาศข้อมูลอธิบายส่วนต่าง ๆ ของโค้ด เช่น Class, Method, Function, Property หรือ Parameter โดยใช้โครงสร้าง #[AttributeName]

ข้อดีของ Attributes

  1. Native Syntax: ทำงานโดย PHP Core โดยตรง ไม่ต้องพึ่งพา External Parser
  2. Type Safety & Validation: เนื่องจากมันเป็นโค้ด PHP จริง ๆ ถ้าเราพิมพ์ชื่อ Attribute ผิด หรือส่ง Argument ผิดประเภท ตัว PHP จะแจ้ง Syntax Error หรือ ArgumentCountError ทันที
  3. 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 AnnotationsPHP 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 เต็มตัวได้เลยครับ!


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

Exit mobile version