บทความ

PHP 8 มีฟีเจอร์อะไรที่ JavaScript ไม่มีบ้าง

เทียบ syntax ของ PHP 8 กับ JavaScript ทีละตัว named arguments, match และ constructor property promotion ยังไม่มีใน JavaScript ส่วน nullsafe operator นั้น JavaScript มี ?. มาตั้งแต่ ES2020

เผยแพร่
อัปเดต
— แก้ข้อมูลผิด JavaScript มี ?. แล้ว และเพิ่ม constructor property promotion กับ pipe operator
เวลาอ่าน
3 นาที
แท็ก
#PHP

PHP เป็นภาษาที่อยู่มานาน แต่ยังออกเวอร์ชันใหม่ทุกปี (รายการเวอร์ชันบน php.watch) ตั้งแต่เพิ่ม type ให้เช็คได้เข้มขึ้น ไปจนถึง JIT ที่ช่วยเรื่องความเร็ว PHP 8 ก็เพิ่ม syntax ที่ทำให้โค้ดสั้นและอ่านง่ายขึ้นหลายตัว

โพสต์นี้หยิบ syntax เหล่านั้นมาเทียบกับ JavaScript ทีละตัว ว่าฝั่ง JavaScript มีหรือยัง ถ้ายังไม่มี เราเขียนแทนกันยังไง ตัวอย่างฝั่ง PHP เช็คกับ PHP 8.4 แล้ว

1. Named arguments ส่งค่าตามชื่อ parameter (JavaScript ไม่มี)

สมมุติเรามีฟังก์ชันแบบนี้

function savePost(Post $post, bool $isSticky = false, ?string $imagePath = null): void
{
    // ...
}

ถ้าอยากส่งแค่ $post กับ $imagePath เราเรียกด้วยชื่อ parameter ได้เลย (RFC)

savePost(post: $post, imagePath: $path);

// ผสมกันก็ได้ ใส่แบบตามลำดับไว้ก่อน แล้วตามด้วยแบบมีชื่อ
savePost($post, imagePath: $path);

ไม่ต้องส่ง $isSticky เลย PHP ใช้ค่า default ให้เอง มีประโยชน์มากกับฟังก์ชันที่รับ parameter สัก 4-5 ตัวขึ้นไป ซึ่งเราจำลำดับไม่ค่อยได้ว่าตัวไหนอยู่ตำแหน่งที่เท่าไหร่

JavaScript ยังไม่มี syntax นี้ ถ้าอยากข้าม parameter ตรงกลาง ส่ง undefined ไปแทน แล้ว JavaScript จะใช้ค่า default ของตัวนั้น (MDN) แต่ส่ง null ไม่ได้ เพราะ null นับเป็นค่าที่ส่งมาจริง

savePost(post, undefined, 'path/to/image.jpg');

อีกทางที่ใช้กันมาตลอดคือให้ฟังก์ชันรับ object แล้วแตกค่าด้วย destructuring อ่านแล้วใกล้เคียง named arguments แต่ต้องออกแบบฟังก์ชันให้รับ object ตั้งแต่แรก และคนเรียกต้องห่อค่าเป็น object ทุกครั้ง

function savePost({ post, isSticky = false, imagePath = null }) {
  // ...
}

savePost({ post, imagePath: 'path/to/image.jpg' });

2. match เลือกค่าตามเงื่อนไขในนิพจน์เดียว (JavaScript ไม่มี)

match เป็น syntax ของ PHP 8 ที่ผมใช้บ่อยที่สุดตัวหนึ่ง ใช้แทน switch หรือ array lookup ได้แทบทุกที่ (คู่มือ PHP)

$color = match ($state) {
    'draft' => 'gray',
    'active', 'complete', 'done' => 'primary',
    default => 'secondary',
};

match คืนค่าออกมาให้เก็บใส่ตัวแปรได้ทันที เทียบแบบ === และถ้าไม่มี arm ไหนตรงและไม่มี default PHP จะ throw UnhandledMatchError ให้ อ่านรายละเอียดต่อได้ในโพสต์ syntax ใหม่ของ PHP 8

JavaScript มีแค่ switch ซึ่งเป็น statement คืนค่าไม่ได้ และต้องใส่ break เองทุก case (MDN)

let color;

switch (state) {
  case 'draft':
    color = 'gray';
    break;
  case 'active':
  case 'complete':
  case 'done':
    color = 'primary';
    break;
  default:
    color = 'secondary';
}

ถ้าเทียบค่าคงที่ตรง ๆ แบบนี้ เขียนเป็น object lookup แล้วใช้ ?? ใส่ค่า default จะสั้นกว่า

const colors = { draft: 'gray', active: 'primary', complete: 'primary', done: 'primary' };

const color = colors[state] ?? 'secondary';

ฝั่ง TC39 มี proposal pattern matching ที่ใช้คำว่า match เหมือนกัน แต่ตอนนี้ยังอยู่แค่ Stage 1 ยังไม่มีเบราว์เซอร์ไหนใช้ได้ และ syntax ยังเปลี่ยนได้อีกมาก

3. Constructor property promotion ประกาศ property ใน constructor ทีเดียว (JavaScript ไม่มี)

ใน PHP 8 ใส่ visibility หรือ readonly หน้า parameter ของ constructor แล้ว PHP จะสร้าง property และกำหนดค่าให้เลย (คู่มือ PHP)

class Money
{
    public function __construct(
        public readonly int $amount,
        public readonly string $currency = 'THB',
    ) {}
}

$price = new Money(1500);
$price->currency; // 'THB'

JavaScript ไม่มีแบบนี้ ต้องกำหนดค่าให้ this เองทีละตัว

class Money {
  constructor(amount, currency = 'THB') {
    this.amount = amount;
    this.currency = currency;
  }
}

ถ้าเขียน TypeScript จะมี parameter properties ที่หน้าตาคล้ายของ PHP แต่เป็นความสามารถของ TypeScript ไม่ใช่ JavaScript

4. Nullsafe operator ?-> ตัวนี้ JavaScript มี ?. แล้ว

ถ้าเรียกเมธอดต่อกันหลายชั้น แล้วชั้นไหนคืน null มา PHP จะ error ตอนเรียกเมธอดถัดไป ใส่ ?-> แล้ว PHP จะหยุดทั้ง chain และคืน null ทันทีที่เจอ null (RFC)

$company = auth()->user()?->getDepartment()?->getCompany();

ไม่ว่า user() หรือ getDepartment() จะคืน null โค้ดก็ไม่ error และ $company เป็น null

ฉบับแรกของโพสต์นี้เขียนไว้ว่า JavaScript ไม่มีแบบนี้ ซึ่งผิด JavaScript มี optional chaining ?. มาตั้งแต่ ES2020 (TC39) และใช้ได้ในเบราว์เซอร์หลักทุกตัวตั้งแต่กลางปี 2020 (MDN) ก่อน PHP 8.0 ออกเสียอีก

const company = auth().user()?.getDepartment()?.getCompany();

สองตัวนี้ต่างกันนิดหน่อย

  • ?. ของ JavaScript หยุดเมื่อเจอทั้ง null และ undefined แล้วคืน undefined ส่วน ?-> ของ PHP คืน null
  • JavaScript ใช้ ?. กับ array และการเรียกฟังก์ชันได้ด้วย เช่น items?.[0] หรือ callback?.() ส่วน PHP ใช้ ?-> ได้กับ object เท่านั้น ถ้าเป็น array ใช้ ?? แทน เช่น $data['user']['name'] ?? null

ส่วน null coalescing ?? ทั้งสองภาษามีเหมือนกัน PHP มีตั้งแต่ 7.0 และ JavaScript มีตั้งแต่ ES2020 (MDN)

แล้ว PHP 8.5 มีอะไรที่ JavaScript ยังไม่มีอีก

PHP 8.5 (ออกเมื่อ 20 พ.ย. 68) เพิ่ม pipe operator |> ส่งค่าทางซ้ายเข้าฟังก์ชันทางขวาต่อกันเป็นทอด ๆ อ่านจากซ้ายไปขวาได้เลย ไม่ต้องซ้อนวงเล็บหลายชั้น (RFC)

$slug = $title
    |> trim(...)
    |> strtolower(...)
    |> (fn (string $text): string => str_replace(' ', '-', $text));

JavaScript มี proposal pipeline operator อยู่เหมือนกัน แต่ยังอยู่ Stage 2 ยังใช้จริงไม่ได้ ส่วนฝั่ง PHP ต้องใช้ PHP 8.5 ขึ้นไป ถ้าโปรเจกต์ยังอยู่ PHP 8.3 หรือ 8.4 (Laravel 13 รองรับตั้งแต่ 8.3) ยังใช้ |> ไม่ได้

เทียบกันทั้งหมด

ฟีเจอร์ PHP JavaScript
Named arguments 8.0 ไม่มี ใช้ object กับ destructuring แทน
match 8.0 ไม่มี pattern matching ยังอยู่ Stage 1
Constructor property promotion 8.0 ไม่มี มีใน TypeScript
Nullsafe ?-> / ?. 8.0 มีตั้งแต่ ES2020
Null coalescing ?? 7.0 มีตั้งแต่ ES2020
Pipe operator 8.5 ไม่มี proposal ยังอยู่ Stage 2

อ่านต่อ

ล่าสุด

ดูทั้งหมด →