ทำยังไง? อยากให้ JavaScript เรียกฟังก์ชันในภาษา PHP เขียนโค้ดยังไงนะ
Tags: php, javascript, ajax, tutorial
Published: 2020-08-30 13:12:32

หนึ่งในคำถามที่เว็บโปรแกรมเมอร์มือใหม่ถามกันเยอะมากจนน่าจัดเก็บไว้เป็น FAQ เลยก็คือ

**"จะทำยังไงให้เราเรียกใช้ฟังก์ชันภาษา PHP จากสคริป JavaScript ได้"**

เช่นแบบนี้...

```html
<button onclick="<?php functionInPhp1(); ?>">
    คลิกฉันสิ!
</button>
```

หรือแบบนี้...

```js
function functionInJs(){
    let x = <?php functionInPhp2(); ?>
}
```

คำตอบคือ ด้วยการทำงานของเว็บที่ทำงานบนโปรโตคอล http นั้น...มันทำไม่ได้!! (แต่มีวิธีแก้ ถ้าอยากทำจริงๆ อ่านต่อไป!)

> จริงๆ แล้วไม่จำกัดว่าต้องเป็นภาษา PHP เท่านั้นนะ เคสนี้เป็นกับทุกภาษาฝั่งเซิร์ฟเวอร์เลย

เพื่อจะตอบว่าทำไมมันทำไม่ได้ เราจะต้องอธิบายการทำงานของ http กันซะก่อน

## http และ Stateless

http เป็นโปรโตคอลมาตราฐานสำหรับการเขียนเว็บ ซึ่งการทำงานของมันสรุปง่ายๆ ได้ดังนี้

> โปรโตคอล (Protocol) = กฎที่ตั้งขึ้นมาเพื่อให้คอมพิวเตอร์ในเน็ตเวิร์คสามารถคุยกันด้วยภาษาเดียวกัน ไม่งั้นมันจะคุยกันไม่รู้เรื่อง

![](https://1.bp.blogspot.com/-VOh-OfyOCxw/X0uY8UC54II/AAAAAAAASkE/pNpSfpaDfVc-BqekljFVBOjNiHqhlEpZgCNcBGAsYHQ/s1507/js-call-php-1.png)

- Client ส่งคำขอหรือ `request` ไปหา Server 
- เมื่อ Server ได้รับ `request` แล้วก็จะรันสคริปที่เตรียมไว้ เพื่อหาว่าจะตอบอะไรกลับไปให้ Client, ในสเต็ปนี้ อาจจะมีการเชื่อมต่อเพื่อขอข้อมูลจาก database ด้วย
- หลังจาก Server คิดเสร็จ ก็จะส่งคำตอบ (อยู่ในรูปแบบของ String) กลับไปให้ Client **[มาถึงตรงนี้ถือว่า Server ทำงานเสร็จแล้ว!]**
- Client รับข้อมูลไป (ส่วนใหญ่จะอยู่ในรูปแบบ html) ก็เอาไปแสดงผล แต่ถ้ามีการแนบสคริปมาด้วย ก็จะจัดการรันสคริปตัวนั้นซะในสเต็ปนี้
- จบจ้า!

![](https://1.bp.blogspot.com/-FenJv8vff1o/X0uY8GsJ6DI/AAAAAAAASkA/cKpPnBxLX1cKLrQmkMTwLKYAb2vX3dD_wCNcBGAsYHQ/s1599/js-call-php-2.png)

สำหรับฝั่ง Client นั้นไม่ค่อยมีปัญหาเพราะมีแค่ภาษาเดียวเท่านั้นที่ครอบครองอยู่ นั่นคือ JavaScript แต่ฝั่ง Server นี่มีหลายภาษามากๆ เช่น PHP, Node.js. Go, .NET

แต่ไม่ว่าฝั่งเซิร์ฟเวอร์จะเขียนด้วยภาษาอะไร หน้าที่ของมันคือส่ง HTML, CSS, JS กลับมาให้ Client เพื่อโปรเซสต่อ

จะเห็นว่า http เป็นโปรโตคอลง่ายๆ ถามมา-ตอบกลับ แล้วก็จบงาน

ซึ่งเราเรียกการทำงานแบบนี้ว่า **"Stateless"** คือทำงานเป็นรอบ พอเรียกใช้งานและทำงานนั้นเสร็จแล้ว ก็จบการทำงาน (เว็บส่วนใหญ่ทำงานแบบนี้)

ตรงข้ามกับ **"Stateful"** ที่ตัวโปรแกรมรันค้างอยู่ตลอดเวลา (ให้นึกถึงแอพพลิเคชันมือถือหรือโปรแกรมที่รันใน Desktop)

## Server ทำงานก่อน Client เสมอ!

เราอธิบายให้ฟังแล้วว่า http นั้นเริ่มทำงานที่ Server รันเพื่อโปรเซสข้อมูลที่จะส่งกลับมาให้ Client ก่อน ... แล้วพอ Client ได้รับข้อมูล (ซึ่งอาจจะมี JavaScript แนบติดมาให้ด้วย) ก็จะเอาสคริปตัวนั้นมารันต่อ

แสดงว่าในจังหวะที่ Client เริ่มทำงานนั้น ... โค้ดฝั่ง Server ทำงานเสร็จไปแล้ว !

**นี่เลยเป็นเหตุผลว่าทำไมเราไม่สามารถทำให้ JavaScript เรียกให้ PHP ทำงานได้**

เช่น

```php
<?php
    function registerMeeting(){
        //ต้องการบันทึกว่าเข้าร่วมประชุมแล้ว
    }

    function getOnlines(){
        //ต้องการดึงรายชื่อคนที่กำลังออนไลน์อยู่ในขณะนี้
    }
?>

<button onclick="<?php registerMeeting(); ?>">
    ลงชื่อเข้าประชุม
</button>

<script>
    function getWhoOnlineNow(){
        let onlines = <?php getOnlines(); ?>
    }
</script>
```

ในโค้ดตัวอย่างนี้เรามีฟังก์ชันในภาษา PHP อยู่ 2 ตัว คือ `registerMeeting()` และ `getOnlines()`

จากนั้นเราไปเขียนโค้ด JavaScript เพื่อเรียกใช้งานฟังก์ชัน PHP ทั้งสองตัวนี้ต่อ

แต่ปัญหาก็คือ PHP เป็น Server-Side-Script มันทำงานก่อนเสมอ (ไม่ต้องรอให้ JavaScript เรียกหรอก ฉันทำงานเองตอนนี้เลย!)

แต่ด้วยโลจิคแล้ว เราต้องการให้ฟังก์ชันพวกนี้ทำงานเมื่อเรามี event เท่านั้น (เชื่อ ปุ่มโดน onclick หรือฟังก์ชัน JavaScript ทำงาน)

ดังนั้นโค้ดนี้เลยผิด! 

## Asynchronous คือทางแก้

หากต้องการให้ JavaScript เรียกให้ PHP ทำงานได้ มีอยู่วิธีเดียวนั้นคือใช้เทคนิคการเขียนโปรแกรมแบบ Asynchronous 

หรือถ้าจะเรียกด้วยชื่อแบบดังเดิมคือเทคนิคที่เรียกว่า **"Ajax"** (**A**synchronous **J**avaScript **a**nd **X**ML) ... แต่ปัจจุบันไม่ค่อยเรียกชื่อนี้กันแล้วนะ และเราก็ไม่ได้ใช้แค่ XML เป็นตัวกลางส่งข้อมูลกันอีกตัวไป มีการใช้ JSON เพิ่มเข้ามาด้วย


> ในบทความนี้จะไม่สอน Ajax แบบละเอียดนะ ถ้าอยากรู้ตามไปอ่านได้ที่ [Ajax คืออะไร แล้วมันใช้ยังไง?](https://www.tamemo.com/post/37/how-to-ajax-1/)

สำหรับ PHP ...

ให้แยกโค้ดส่วนที่ต้องการให้ JavaScript เรียกใช้งานได้ออกมาอยู่อีกไฟล์หนึ่ง เช่นกรณีนี้ตั้งชื่อไฟล์ว่า `async-handler.php`

```php
FILE: async-handler.php

<?php
function registerMeeting(){
    //ต้องการบันทึกว่าเข้าร่วมประชุมแล้ว
}

function getOnlines(){
    //ต้องการดึงรายชื่อคนที่กำลังออนไลน์อยู่ในขณะนี้
}

switch($_GET['action']){
    case 'register-meeting': 
        registerMeeting(); 
        break;
    case 'get-online-user': 
        getOnlines(); 
        break;
}
```

และเนื่องจากเรามี action ที่ต้องการให้ทำงานมากกว่า 1 ตัว ก็เลยใช้ query-string ชื่อว่า `action` เป็นตัวแยกว่า request ครั้งนี้ต้องการให้ฟังก์ชันไหนทำงาน (ตรงนี้ตั้งชื่อว่าอะไรก็ได้นะ แล้วแต่เลย)


```html
<button onclick="registerMeeting()">
    ลงชื่อเข้าประชุม
</button>

<script>
    function registerMeeting(){
        fetch('/async-handler.php?action=register-meeting')
    }

    function getWhoOnlineNow(){
        fetch('/async-handler.php?action=get-online-user')
        .then(onlines => {
            ...
        })
    }
</script>
```

จากนั้น ในฝั่ง JavaScript ก็ใช้การ request กลับไปยังไฟล์ PHP `async-handler.php` ที่เตรียมไว้อีกรอบ จะใช้คำสั่ง `fetch()` หรือไลบรารี่ Axios หรือถ้าเก่าหน่อยก็ใช้ `$.ajax()` ของ jQuery ก็ตามสะดวกเลย

## สรุป

การจะให้ JavaScript เรียกคำสั่ง PHP ตรงๆ นั้นทำไม่ได้ เพราะกว่า JavaScript จะเริ่มทำงาน PHP ก็ทำงานจนเสร็จไปก่อนแล้ว

![](https://1.bp.blogspot.com/-VSzWK6n8NLQ/X0uix11l-0I/AAAAAAAASkU/YS4xQp5zbJIRUW88MNV94_9QBfUSXUlAQCNcBGAsYHQ/s1192/js-call-php-3.png)

แต่มีวิธีการแก้ทางคือสร้าง request ขึ้นมาอีกครั้งเพื่อเรียกไปหา Server ให้ปลุก PHP ขึ้นมาทำงานอีกรอบหนึ่ง

คือต้อง request 2 ครั้ง
- ครั้งแรก - ให้ Server ส่ง HTML, CSS, JS มาให้ก่อน
- ครั้งที่สอง - JavaScript สร้าง request อีกครั้ง เรียกไปยังไฟล์ PHP ที่เตรียมเป็น asynchronous handler เอาไว้