ทำยังไง? อยากให้ JavaScript เรียกฟังก์ชันในภาษา PHP เขียนโค้ดยังไงนะ

js-call-php-cover

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

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

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

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

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

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

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

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

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

http และ Stateless

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

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

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

สำหรับฝั่ง 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
    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" (Asynchronous JavaScript and XML) ... แต่ปัจจุบันไม่ค่อยเรียกชื่อนี้กันแล้วนะ และเราก็ไม่ได้ใช้แค่ XML เป็นตัวกลางส่งข้อมูลกันอีกตัวไป มีการใช้ JSON เพิ่มเข้ามาด้วย

ในบทความนี้จะไม่สอน Ajax แบบละเอียดนะ ถ้าอยากรู้ตามไปอ่านได้ที่ Ajax คืออะไร แล้วมันใช้ยังไง?

สำหรับ PHP ...

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

<?php
//FILE: async-handler.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 ครั้งนี้ต้องการให้ฟังก์ชันไหนทำงาน (ตรงนี้ตั้งชื่อว่าอะไรก็ได้นะ แล้วแต่เลย)

<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 ก็ทำงานจนเสร็จไปก่อนแล้ว

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

คือต้อง request 2 ครั้ง

  • ครั้งแรก - ให้ Server ส่ง HTML, CSS, JS มาให้ก่อน
  • ครั้งที่สอง - JavaScript สร้าง request อีกครั้ง เรียกไปยังไฟล์ PHP ที่เตรียมเป็น asynchronous handler เอาไว้
Share on facebook
Facebook
Share on google
Google+
Share on twitter
Twitter
Share on linkedin
LinkedIn
Share on pinterest
Pinterest

Recent Post

ปี2020, จริงๆ เราไม่ต้องใช้ jQuery แล้วก็ได้นะ

jQuery เป็นหนึ่งใน JavaScript Library ที่โด่งดังมาก (เมื่อ 10 ปีที่แล้ว) เรียกว่าในยุคนั้นแทบจะทุกเว็บจะต้องมีการติดตั้ง jQuery เอาไว้อย่างแน่นอน แต่เมื่อยุคสมัยเปลี่ยนไป เบราเซอร์ใหม่ๆ ไม่มีปัญหาการรัน JavaScript ตั้งแต่ ES6 ขึ้นไปแล้ว การใช้งาน jQuery จึงลดน้อยลงเรื่อยๆ แต่ก็มีบางโปรเจคเหมือนกัน ที่เราต้องเข้าไปแก้โค้ดเก่าๆ ซึ่งเขียนด้วย jQuery เอาไว้ ในบทความนี้จะมาเปรียบเทียบว่าทุกวันนี้เราสามารถแปลง jQuery ให้กลายเป็น Vanilla

Vue3 มีอะไรเปลี่ยนแปลงไปบ้าง

Vue 3 เพิ่งเปิดตัวมาเมื่อเดือนที่แล้ว ซึ่งมาพร้อมกับฟีเจอร์ใหม่ๆ และสิ่งที่เปลี่ยนแปลงไป เรามาดูกันดีกว่า เขียนใหม่ด้วย TypeScript ภาษา JavaScript นั้นไม่มี Type ของตัวแปรทำให้เวลาเขียนโปรแกรมมีโอกาสเกิดข้อผิลพลาดเยอะ ดังนั้นการเขียนงานโปรเจคใหญ่ๆ คนเลยนิยมเปลี่ยนไปใช้ TypeScript แทน (ถ้ายังไม่รู้จัก TypeScript อ่านต่อได้ที่นี่) สำหรับ Vue 3.0 นี้ก็เป็นการเขียนใหม่ด้วย TypeScript แทน แต่เวลาเราเอามาใช้งาน เราสามารถเลือกได้ว่าจะใช้แบบ JavaScript ตามปกติ

สอนใช้ TypeScript ในโปรเจค Node.js + Express

Node.js กับ TypeScript Node.js เป็นหนึ่งในเฟรมเวิร์คยอดนิยมสำหรับเขียนโปรแกรมฝั่ง Backend แต่เพราะมันสร้างมาตั้งแต่ปี 2009 ยุคที่ JavaScript ยังเป็นเวอร์ชัน ES5 อยู่เลย โดยดีฟอลต์แล้ว Node.js เลยไม่ซัพพอร์ท TypeScript เลย ไม่เหมือนกับ Deno ที่เพิ่งสร้างขึ้นมาโดยซัพพอร์ท TypeScript เป็นค่า default ตั้งแต่แรก เพื่อชีวิตที่ดีกว่า มาเซ็ตโปรเจค Node.js + Express

UX UI Design เบื้องต้น Section 1 “พื้นฐาน UX UI”

จากที่เราได้รู้จักโลกของ UX UI ไปใน Section ที่แล้ว ใน Section นี้ เราจะมาเข้าใจให้ลึกขึ้นอีกนิด สำหรับ UX UI Design โดยมีคำกล่าวสั้นๆว่า UX คือ นามธรรม UI คือ รูปธรรม และในพื้นฐานแรก ที่เราจะมาเริ่มเรียนรู้คือ UI Design เคลียร์กันชัดๆ UI Design คืออะไร? นิยามของ

ทำยังไง? อยากให้ JavaScript เรียกฟังก์ชันในภาษา PHP เขียนโค้ดยังไงนะ

หนึ่งในคำถามที่เว็บโปรแกรมเมอร์มือใหม่ถามกันเยอะมากจนน่าจัดเก็บไว้เป็น FAQ เลยก็คือ "จะทำยังไงให้เราเรียกใช้ฟังก์ชันภาษา PHP จากสคริป JavaScript ได้" เช่นแบบนี้... <button onclick="<?php functionInPhp1(); ?>"> คลิกฉันสิ! </button> หรือแบบนี้... function functionInJs(){ let x = <?php functionInPhp2(); ?> } คำตอบคือ ด้วยการทำงานของเว็บที่ทำงานบนโปรโตคอล http นั้น...มันทำไม่ได้!! (แต่มีวิธีแก้

[How To] การติดตั้ง Google Maps for Flutter เบื้องต้น

วันนี้ผมจะมาแนะนำและวิธีการใช้งานเบื้องต้นของ plugin ที่น่าสนใจตัวหนึ่งที่มีชื่อว่า "Google Maps for Flutter" โดย plugin ตัวนี้จะให้ Google Maps ที่เป็น Widget มาให้เราได้เปิดใช้งานแผนที่ของกูเกิ้ล ขั้นตอนการติดตั้ง อันดับแรก เราต้องทำการขอ API Key ที่ลิ้งค์ https://cloud.google.com/maps-platform/ เมื่อเข้ามาหน้าเว็บไซต์แล้วให้เข้าไปที่ Console (ตรงขวามุมบนของหน้าจอ) สร้าง Project ของเราขึ้นมาก่อน เมื่อทำการสร้างเสร็จแล้วให้เปิดแท็บด้านขวามือ แล้วเลือกเมนูที่ชื่อว่า

UX UI Design เบื้องต้น Section 0 “โลกของ UX UI”

หากเปรียบเทียบการออกแบบ UX UI เป็นประตู ดังนั้น Designer คือผู้ที่ต้องแก้ไขปัญหา เพื่อให้ตอบโจทย์ผู้ใช้ ไม่ใช่คำนึงแค่ความสวยงามเท่านั้น โดยใน Sec.0 นี้ เราจะมองภาพง่ายๆแบบใกล้ตัว เช่น การออกแบบประตู ซึ่งการออกแบบ เราจะมีพื้นฐานด้วยกัน 4 อย่าง ดังนี้ พื้นฐานการออกแบบมี 4 อย่าง คือ การออกแบบหน้าตา (User Interface Design) :: หน้าตาของประตู

สอนวิธีเซ็ตโปรเจค TypeScript / มาใส่ไทป์ให้ JavaScript เพื่อลดความผิดพลาดในการเขียนโค้ดกันดีกว่า

ภาษา JavaScript นั้นเป็นภาษาที่เริ่มเขียนได้ไม่ยาก ยิ่งถ้าใครเขียนภาษาสาย Structure/OOP เช่น C/C++, C#, Java มาก่อน อาจจะชอบในความเป็น Dynamic Type เราสร้างตัวแปรแล้วเก็บค่าอะไรก็ได้ ทำให้มีความคล่องตัวในการเขียนมากๆ ก่อนที่พอเขียนไปเรื่อยๆ เราจะพบความแปลกของมัน ยิ่งเขียนไปนานๆ เราก็พบว่ามันเป็นภาษาที่ทำให้เกิดบั๊กได้ง่ายมาก และเป็นหนึ่งในภาษาที่น่าปวดหัวที่สุดที่คนโหวตๆ กันเลย ด้วยเหตุผลแรกคือการที่ตัวแปรไม่มี Type นั่นเอง (อีกเหตุผลหนึ่งคือส่วนใหญ่ของคนที่เปลี่ยนมาเขียน JavaScript เคยชินกับภาษาแนว OOP มาก่อน พอมาเขียนภาษาแนว

รู้จักกับ TypeScript – ประวัติของภาษาที่เติมไทป์ให้กับ JavaScript

ในบทความนี้จะเล่าถึงที่มาที่ไปของ TypeScript อย่างเดียวนะ ส่วนเรื่องสอนว่าใช้งานยังไงได้บ้าง จะเขียนอีกทีในบล็อกต่อๆ ไป สำหรับภาษาโปรแกรมทุกวันนี้ ถ้าแบ่งคร่าวๆ ด้วยชนิดของตัวแปร เราจะแบ่งได้ 2 อย่าง คือ Static Type: ต้องกำหนดชนิดตัวแปร เช่น int, string ตั้งแต่สร้างตัวแปร และ Dynamic Type ตัวแปรประเภทนี้ไม่ต้องบอกว่าเก็บค่าชนิดไหน เปลี่ยนไปได้เรื่อยๆ สำหรับภาษาแบบ Dynamic Type ที่ไม่ต้องกำหนดชนิดตัวแปรให้แน่นอน จะเซ็ตค่าเป็นอะไรก็ได้นั้นอาจจะทำให้เขียนง่าย

Async in Dart (5) รู้จักกับ FutureBuilder/StreamBuilder, ตัวช่วยสร้าง Async-Widget ใน Futter

เนื้อหาในบทนี้ เป็นคลาสเฉพาะที่มากับ Flutter Framework เท่านั้น .. ถ้าเขียน Dart ธรรมดาจะไม่มีให้ใช้นะ!! เอาจริงๆ 99% ของคนที่ศึกษาภาษา Dart ก็เพื่อเอาไปเขียนแอพ (หรือเว็บ/เด็กส์ท็อป) แบบ cross-platform ด้วยเฟรมเวิร์ก Flutter นั่นแหละ ตามความคิดของเรา จริงๆ Flutter น่าจะเลือกภาษา Kotlin มาใช้แทนมากกว่า แต่ก็มีเหตุผลหลายๆ อย่างนั่นแหละที่ทำให้ทำไม่ได้ สำหรับการเขียน Flutter

Dependency Injection กับ Service Locator ต่างกันยังไงนะ?

ในโลกของ OOP เรามักจะสร้างคลาสต่างๆ ที่มีการเรียกใช้กันต่อเป็นทอดๆ มากมาย เช่นโค้ดข้างล่างนี่ class Car { private Engine engine; public Car() { this.engine = new Engine(); } } Car car = new Car(); เราสร้างคลาส Car และ Engine

Async in Dart (4) ควบคุมข้อมูลในstreamอย่างเหนือชั้นด้วย StreamController

Async in Dart (4) ควบคุมข้อมูลในstreamอย่างเหนือชั้นด้วย StreamController ในบทที่แล้วเราสอนการสร้าง Stream แบบง่ายๆ ไปแล้ว แต่ในบางครั้งเราต้องการควบคุมข้อมูลใน Stream แบบคัสตอมมากๆ ซึ่งข้อมูลอาจจะเข้ามาจากหลายทางมากๆ การที่เรามีแค่ yield จากฟังก์ชันเดียวอาจจะไม่เพียงพอ ดังนั้นเลยเป็นที่มาของคลาสที่ชื่อว่า StreamController ซึ่งเป็นคลาสที่เอาไว้ควบคุม Stream อีกที StreamController การสร้าง Stream แบบธรรมดาก็จะเป็นประมาณนี้ Stream<int> getNumberStream() async* {