PhalconPHP: โซลูชันสำหรับ RESTful API ที่มีโหลดสูง

เผยแพร่แล้ว: 2022-03-11

สมมติว่าคุณต้องสร้างโครงการที่มีภาระงานสูงตามกรอบงาน PHP MVC คุณอาจจะใช้การแคชทุกที่ที่ทำได้ บางทีคุณอาจจะสร้างโปรเจ็กต์ในไฟล์เดียว หรือแม้แต่เขียนเฟรมเวิร์ก MVC ของคุณเองโดยใช้ฟังก์ชันที่น้อยที่สุด หรือเขียนบางส่วนของเฟรมเวิร์กอื่นใหม่ ในขณะที่ใช่มันใช้งานได้มันค่อนข้างยุ่งยากใช่ไหม โชคดีที่มีอีกวิธีหนึ่งที่ทำให้การจัดการเหล่านี้ส่วนใหญ่ไม่จำเป็น (บางทีอาจจะประหยัดสำหรับแคช) และโซลูชันนี้เรียกว่าเฟรมเวิร์ก PhalconPHP

PhalconPHP คืออะไร?

PhalconPHP เป็นเฟรมเวิร์ก MVC สำหรับ PHP ที่เขียนด้วยภาษา C และจัดทำเป็นส่วนขยาย PHP ที่คอมไพล์แล้ว นี่คือสิ่งที่ทำให้มันเป็นหนึ่งในเฟรมเวิร์กที่เร็วที่สุดที่มีอยู่ (ตามจริงแล้วเฟรมเวิร์กที่เร็วที่สุดคือ Yaf แต่เป็นไมโครเฟรมเวิร์กและมีฟังก์ชันการทำงานที่จำกัดมากกว่า Phalcon มาก) PhalconPHP ไม่ต้องการการดำเนินการที่ยาวนานใดๆ กับไฟล์ PHP และไม่จำเป็นต้องตีความทุกคำขอ — ไฟล์จะถูกโหลดลงใน RAM ครั้งเดียวเมื่อเว็บเซิร์ฟเวอร์ของคุณเริ่มทำงานและใช้ทรัพยากรน้อยมาก

เฟรมเวิร์ก MVC ได้รับการพิจารณาว่าเป็นแนวทางปฏิบัติที่ดีที่สุดในการพัฒนาเว็บมาเป็นเวลานานแล้ว ตอนนี้มันเป็นมาตรฐานระดับมืออาชีพ ดังนั้นนักพัฒนาเว็บส่วนใหญ่จึงคุ้นเคยกับเฟรมเวิร์ก MVC อย่างน้อยหนึ่งเฟรมสำหรับ PHP: Symfony, Yii, Laravel, CodeIgniter, Zend กรอบงาน ฯลฯ พวกเขาแต่ละคนมีข้อดีและข้อเสียของตัวเอง แต่สิ่งที่พวกเขาทั้งหมดมีเหมือนกัน? ทั้งหมดเขียนด้วย PHP และประกอบด้วยไฟล์ PHP จำนวนมากที่มีตรรกะจำนวนมาก ซึ่งล่ามต้องเรียกใช้ในทุกคำขอ ทุกครั้งที่โค้ดของคุณทำงาน แม้ว่าสิ่งนี้จะทำให้เกิดความโปร่งใส แต่เราจ่ายด้วยประสิทธิภาพ โค้ดจำนวนมากและไฟล์ที่รวมอยู่จำนวนมากใช้หน่วยความจำและเวลาอย่างมาก โดยเฉพาะอย่างยิ่งใน PHP (เนื่องจากถูกตีความ ไม่ใช่คอมไพล์) ใช่ สถานการณ์ดีขึ้นมากใน PHP 7 แต่ยังมีอะไรที่ต้องปรับปรุงอีกมาก และ PhalconPHP นำการปรับปรุงเหล่านั้นมาสู่ตาราง

ลองมาดูที่เกณฑ์มาตรฐานบางอย่าง

PhalconPHP เกณฑ์มาตรฐาน

เกณฑ์มาตรฐานอย่างเป็นทางการมีอายุ 5 ปี ซึ่งเก่าเกินไปที่จะใช้ได้ในขณะนี้ แต่ถึงอย่างนั้นคุณก็มองเห็นความแตกต่างของ PhalconPHP ได้อย่างมาก มาดูของใหม่กันดีกว่า ในการเปรียบเทียบปี 2559 Phalcon ติดอันดับห้าอันดับแรก—เป็นผู้นำที่ชัดเจนในกลุ่มเฟรมเวิร์กระดับมืออาชีพ และยอมรับเฉพาะ PHP ดิบและไมโครเฟรมเวิร์กบางตัวเท่านั้น

เกณฑ์มาตรฐาน PhalconPHP

ดังนั้น Phalcon จึงเร็ว Raw PHP ก็รวดเร็วเช่นกัน แต่เราต้องการสิ่งอำนวยความสะดวกทั้งหมดที่เฟรมเวิร์ก MVC มีให้ และ Phalcon ก็ก้าวไปสู่ความท้าทาย ซึ่งรวมถึงส่วนประกอบต่างๆ เช่น:

  • ORM
  • แม่แบบโวลต์ เครื่องยนต์
  • คอนเทนเนอร์การฉีดพึ่งพา (DI)
  • เก็บเอาไว้
  • การบันทึก
  • ระบบการกำหนดเส้นทาง
  • บล็อกความปลอดภัย
  • โหลดอัตโนมัติ
  • โมดูลแบบฟอร์ม

นั่นเป็นเพียงเพื่อชื่อไม่กี่ เพื่อสรุปเรื่องยาว PhalconPHP มีทุกสิ่งที่คุณต้องการเพื่อสร้างแอปพลิเคชันองค์กรขนาดใหญ่ เช่น RESTful API สำหรับระบบที่มีภาระงานสูง

ข้อดีอีกอย่างของ Phalcon คือสไตล์เล็กๆ—แค่เปรียบเทียบ Phalcon ORM กับ Doctrine 2 ที่ใหญ่โต

มาดูการสร้างโปรเจ็กต์ PhalconPHP กัน

โครงการ Phalcon สองประเภท: Full-stack และ Micro

โดยทั่วไป เฟรมเวิร์ก MVC มีอยู่สองประเภท: เฟรมเวิร์กฟูลสแตก (เช่น Symfony, Yii) และเฟรมเวิร์กไมโคร (เช่น Lumen, Slim, Silex)

เฟรมเวิร์กฟูลสแตกเป็นตัวเลือกที่ดีสำหรับโปรเจ็กต์ขนาดใหญ่ เนื่องจากมีฟังก์ชันการทำงานที่มากกว่า แต่ต้องการคุณสมบัติและเวลาในการดำเนินการอีกเล็กน้อย

ไมโครเฟรมเวิร์กช่วยให้คุณสร้างต้นแบบน้ำหนักเบาได้อย่างรวดเร็ว แต่ไม่มีฟังก์ชันการทำงาน ดังนั้นโดยทั่วไปควรหลีกเลี่ยงการใช้ต้นแบบเหล่านี้สำหรับโครงการขนาดใหญ่ ข้อดีอย่างหนึ่งของไมโครเฟรมเวิร์กคือประสิทธิภาพ โดยปกติแล้วจะเร็วกว่า full-stack มาก (เช่น กรอบงาน Yaf มีประสิทธิภาพต่ำกว่า PHP ดิบเท่านั้น)

PhalconPHP รองรับทั้งสองอย่าง: คุณสามารถสร้างฟูลสแตกหรือไมโครแอปพลิเคชัน ยิ่งไปกว่านั้น เมื่อคุณพัฒนาโปรเจ็กต์ของคุณใน PhalconPHP เป็นไมโครแอปพลิเคชัน คุณยังคงสามารถเข้าถึงคุณลักษณะอันทรงพลังส่วนใหญ่ของ Phalcon และประสิทธิภาพของมันยังคงเร็วกว่าแอปพลิเคชันแบบฟูลสแตก

ที่งานที่ผ่านมา ทีมของฉันจำเป็นต้องสร้างระบบ RESTful ที่มีโหลดสูง สิ่งหนึ่งที่เราทำคือเปรียบเทียบประสิทธิภาพต้นแบบระหว่างแอปพลิเคชันฟูลสแตกใน Phalcon กับแอปพลิเคชันขนาดเล็กของ Phalcon เราพบว่าไมโครแอปพลิเคชันของ PhalconPHP มีแนวโน้มที่จะเร็วกว่ามาก ฉันไม่สามารถแสดงการวัดประสิทธิภาพใดๆ แก่คุณเนื่องจากเหตุผลของ NDA แต่ในความคิดของฉัน หากคุณต้องการใช้ประโยชน์จากประสิทธิภาพของ Phalcon ให้เกิดประโยชน์สูงสุด ให้ใช้ไมโครแอปพลิเคชัน แม้ว่าไมโครแอปพลิเคชันจะสะดวกน้อยกว่าเมื่อเทียบกับฟูลสแตก แต่ไมโครแอปพลิเคชันของ PhalconPHP ยังคงมีทุกสิ่งที่คุณต้องการสำหรับโครงการของคุณและประสิทธิภาพที่ดีขึ้น เพื่อแสดงให้เห็น ให้เขียน RESTful micro application แบบง่ายๆ ใน Phalcon

การสร้าง RESTful API

การเรียงสับเปลี่ยนเกือบทั้งหมดของแอปพลิเคชัน RESTful มีสิ่งหนึ่งที่เหมือนกัน: เอนทิตี User ดังนั้น สำหรับโครงการตัวอย่างของเรา เราจะสร้างแอปพลิเคชัน REST ขนาดเล็กเพื่อสร้าง อ่าน อัปเดต และลบผู้ใช้ (หรือที่เรียกว่า CRUD)

คุณสามารถเห็นโครงการนี้เสร็จสมบูรณ์ได้ที่ที่เก็บ GitLab ของฉัน มีสองสาขาเพราะฉันตัดสินใจแบ่งโปรเจ็กต์นี้ออกเป็นสองส่วน: สาขาแรก master มีฟังก์ชันพื้นฐานเท่านั้นโดยไม่มีคุณสมบัติ PhalconPHP เฉพาะ ในขณะที่ส่วนที่สองคือ logging-and-cache มีฟังก์ชันการบันทึกและแคชของ Phalcon คุณสามารถเปรียบเทียบและดูว่าการนำฟังก์ชันดังกล่าวไปใช้ใน Phalcon นั้นง่ายเพียงใด

การติดตั้ง

ฉันจะไม่ทำการติดตั้ง: คุณสามารถใช้ฐานข้อมูล ระบบปฏิบัติการใด ๆ และเว็บเซิร์ฟเวอร์ใดก็ได้ที่คุณต้องการ มีการอธิบายไว้อย่างดีในเอกสารการติดตั้งอย่างเป็นทางการ ดังนั้นเพียงทำตามคำแนะนำโดยขึ้นอยู่กับระบบปฏิบัติการของคุณ

บันทึกการติดตั้งเว็บเซิร์ฟเวอร์ยังมีอยู่ในเอกสารอย่างเป็นทางการของ Phalcon

โปรดทราบว่าเวอร์ชัน PHP ของคุณไม่ควรน้อยกว่า 5.6

ฉันใช้ Ubuntu 16.10, PostgreSQL 9.5.6, Nginx 1.10.0, PHP 7 และ Phalcon 3.0 ฉันได้รวมตัวอย่างการกำหนดค่า Nginx และไฟล์ดัมพ์ PostgreSQL ไว้ในโปรเจ็กต์แล้ว ดังนั้นอย่าลังเลที่จะใช้ หากคุณต้องการการกำหนดค่าอื่น การเปลี่ยนแปลงนั้นทำได้ไม่ยาก

โครงสร้างและการกำหนดค่าโครงการ

ขั้นแรก สร้างโครงสร้างโครงการเริ่มต้น

แม้ว่า Phalcon จะให้คุณใช้โครงสร้างใดก็ได้ตามต้องการ แต่โครงสร้างที่ฉันเลือกสำหรับแบบฝึกหัดนี้ใช้รูปแบบ MVC บางส่วน เราไม่มีมุมมองเพราะเป็นโปรเจ็กต์ RESTful แต่เรามีคอนโทรลเลอร์และโมเดล แต่ละตัวมีโฟลเดอร์และบริการของตัวเอง บริการคือคลาสที่ใช้ตรรกะทางธุรกิจของโครงการ โดยแบ่งส่วน "แบบจำลอง" ของ MVC ออกเป็นสองส่วน: โมเดลข้อมูล (ซึ่งสื่อสารกับฐานข้อมูล) และโมเดลตรรกะทางธุรกิจ

index.php ซึ่งอยู่ในโฟลเดอร์ public เป็นไฟล์บูตที่โหลดส่วนประกอบและการกำหนดค่าที่จำเป็นทั้งหมด โปรดทราบว่าไฟล์การกำหนดค่าทั้งหมดของเราอยู่ในโฟลเดอร์การกำหนด config เราสามารถใส่สิ่งเหล่านี้ในไฟล์บูตสแตรป (และนี่คือวิธีที่แสดงในเอกสารอย่างเป็นทางการ) แต่ในความคิดของฉัน สิ่งนี้ไม่สามารถอ่านได้ในโครงการขนาดใหญ่ ดังนั้นฉันชอบการแยกโฟลเดอร์จากจุดเริ่มต้นมาก

กำลังสร้าง index.php

การผ่านครั้งแรกของเราที่ index.php จะโหลดการกำหนดค่าและโหลดคลาสอัตโนมัติ จากนั้นจึงเริ่มต้นเส้นทาง คอนเทนเนอร์การฉีดการพึ่งพา และไมโครแอปพลิเคชัน PhalconPHP จากนั้นจะส่งการควบคุมไปยังแกนหลักของแอปพลิเคชันขนาดเล็ก ซึ่งจะจัดการคำขอตามเส้นทาง เรียกใช้ตรรกะทางธุรกิจ และส่งคืนผลลัพธ์

มาดูโค้ดกัน:

 <?php try { // Loading Configs $config = require(__DIR__ . '/../app/config/config.php'); // Autoloading classes require __DIR__ . '/../app/config/loader.php'; // Initializing DI container /** @var \Phalcon\DI\FactoryDefault $di */ $di = require __DIR__ . '/../app/config/di.php'; // Initializing application $app = new \Phalcon\Mvc\Micro(); // Setting DI container $app->setDI($di); // Setting up routing require __DIR__ . '/../app/config/routes.php'; // Making the correct answer after executing $app->after( function () use ($app) { // Returning a successful response } ); // Processing request $app->handle(); } catch (\Exception $e) { // Returning an error response }

การกำหนดค่า \Phalcon\Config Object

มีหลายวิธีในการจัดเก็บไฟล์การกำหนดค่าใน Phalcon:

  • ไฟล์ YAML
  • ไฟล์ JSON
  • ไฟล์ INI
  • อาร์เรย์ PHP

การจัดเก็บการกำหนดค่าของคุณในอาร์เรย์ PHP เป็นตัวเลือกที่เร็วที่สุด และเนื่องจากเรากำลังเขียนแอปพลิเคชันที่มีภาระงานสูงและไม่จำเป็นต้องทำให้ประสิทธิภาพการทำงานช้าลง นี่คือสิ่งที่เราจะทำ โดยเฉพาะอย่างยิ่ง เราจะใช้อ็อบเจ็กต์ \Phalcon\Config เพื่อโหลดตัวเลือกการกำหนดค่าของเราลงในโปรเจ็กต์ เราจะมีออบเจ็กต์การกำหนดค่าที่สั้นมาก:

 <?php return new \Phalcon\Config( [ 'database' => [ 'adapter' => 'Postgresql', 'host' => 'localhost', 'port' => 5432, 'username' => 'postgres', 'password' => '12345', 'dbname' => 'articledemo', ], 'application' => [ 'controllersDir' => "app/controllers/", 'modelsDir' => "app/models/", 'baseUri' => "/", ], ] );

ไฟล์นี้มีการกำหนดค่าพื้นฐานสองแบบ แบบหนึ่งสำหรับฐานข้อมูลและอีกแบบสำหรับแอปพลิเคชัน เห็นได้ชัดว่า การกำหนดค่าฐานข้อมูลใช้สำหรับเชื่อมต่อกับฐานข้อมูล และสำหรับอาร์เรย์ application เราจำเป็นต้องใช้ในภายหลัง เนื่องจากเครื่องมือระบบของ Phalcon ใช้การกำหนดค่านี้ คุณสามารถอ่านรายละเอียดเพิ่มเติมเกี่ยวกับการกำหนดค่า Phalcon ได้ในเอกสารอย่างเป็นทางการ

การกำหนดค่า loader.php

มาดูไฟล์กำหนดค่าถัดไปของเรา loader.php ไฟล์ loader.php ลงทะเบียนเนมสเปซกับไดเร็กทอรีที่เกี่ยวข้องผ่านอ็อบเจกต์ \Phalcon\Loader ง่ายยิ่งขึ้นไปอีก:

 <?php $loader = new \Phalcon\Loader(); $loader->registerNamespaces( [ 'App\Services' => realpath(__DIR__ . '/../services/'), 'App\Controllers' => realpath(__DIR__ . '/../controllers/'), 'App\Models' => realpath(__DIR__ . '/../models/'), ] ); $loader->register();

ตอนนี้คลาสทั้งหมดจากเนมสเปซเหล่านี้จะถูกโหลดและพร้อมใช้งานโดยอัตโนมัติ หากคุณต้องการเพิ่มเนมสเปซและไดเร็กทอรีใหม่ เพียงเพิ่มบรรทัดในไฟล์นี้ คุณยังสามารถหลีกเลี่ยงการใช้เนมสเปซโดยการลงทะเบียนไดเร็กทอรีเฉพาะหรือไฟล์เฉพาะ ความเป็นไปได้ทั้งหมดนี้มีอธิบายไว้ในเอกสารประกอบของตัวโหลด PhalconPHP

การกำหนดค่าคอนเทนเนอร์การฉีดการพึ่งพา

เช่นเดียวกับเฟรมเวิร์กร่วมสมัยอื่น ๆ Phalcon ใช้รูปแบบการพึ่งพา (DI) ออบเจ็กต์จะถูกเตรียมใช้งานในคอนเทนเนอร์ DI และสามารถเข้าถึงได้จากออบเจ็กต์ ในทำนองเดียวกัน คอนเทนเนอร์ DI เชื่อมต่อกับออบเจ็กต์แอปพลิเคชัน และจะสามารถเข้าถึงได้จากคลาสทั้งหมดที่สืบทอดมาจากคลาส \Phalcon\DI\Injectable เช่น ตัวควบคุมและบริการของเรา

รูปแบบ DI ของ Phalcon นั้นทรงพลังมาก ฉันถือว่าองค์ประกอบนี้เป็นหนึ่งในส่วนที่สำคัญที่สุดในเฟรมเวิร์กนี้ และฉันขอแนะนำอย่างยิ่งให้คุณอ่านเอกสารประกอบทั้งหมดเพื่อทำความเข้าใจวิธีการทำงาน เป็นกุญแจสำคัญในการทำงานหลายอย่างของ Phalcon

ลองมาดูที่บางส่วนของพวกเขา ไฟล์ di.php ของเราจะมีลักษณะดังนี้:

 <?php use Phalcon\Db\Adapter\Pdo\Postgresql; // Initializing a DI Container $di = new \Phalcon\DI\FactoryDefault(); /** * Overriding Response-object to set the Content-type header globally */ $di->setShared( 'response', function () { $response = new \Phalcon\Http\Response(); $response->setContentType('application/json', 'utf-8'); return $response; } ); /** Common config */ $di->setShared('config', $config); /** Database */ $di->set( "db", function () use ($config) { return new Postgresql( [ "host" => $config->database->host, "username" => $config->database->username, "password" => $config->database->password, "dbname" => $config->database->dbname, ] ); } ); return $di;

อย่างที่คุณเห็น ไฟล์การพึ่งพา (DI) ของเรานั้นซับซ้อนกว่าเล็กน้อยและมีรายละเอียดบางอย่างที่คุณควรระวัง ก่อนอื่น ให้พิจารณาสตริงการเริ่มต้น: $di = new \Phalcon\DI\FactoryDefault(); . เราสร้างวัตถุ FactoryDefault ซึ่งสืบทอด \Phalcon\Di (Phalcon อนุญาตให้คุณสร้างโรงงาน DI ใดก็ได้ที่คุณต้องการ) ตามเอกสาร FactoryDefault “ลงทะเบียนบริการทั้งหมดที่มีให้โดยกรอบงานโดยอัตโนมัติ ด้วยเหตุนี้ ผู้พัฒนาจึงไม่จำเป็นต้องลงทะเบียนแต่ละบริการโดยแยกเป็นเฟรมเวิร์กแบบเต็ม” ซึ่งหมายความว่าบริการทั่วไปเช่น Request และ Response จะสามารถเข้าถึงได้ภายในคลาสเฟรมเวิร์ก คุณสามารถดูรายการบริการดังกล่าวทั้งหมดได้ในเอกสารประกอบการบริการ Phalcon

สิ่งสำคัญต่อไปคือขั้นตอนการตั้งค่า: มีหลายวิธีในการลงทะเบียนบางสิ่งในคอนเทนเนอร์ DI และทั้งหมดนี้มีคำอธิบายโดยละเอียดในเอกสารการลงทะเบียน PhalconPHP ในโครงการของเรา เราใช้สามวิธี: ฟังก์ชันที่ไม่ระบุชื่อ ตัวแปร และสตริง

ฟังก์ชันที่ไม่ระบุชื่อช่วยให้เราทำหลายสิ่งหลายอย่างในขณะที่เริ่มต้นชั้นเรียน ในโปรเจ็กต์นี้โดยเฉพาะ ก่อนอื่นเราจะแทนที่อ็อบเจ็กต์ Response เพื่อตั้งค่า content-type เป็น JSON สำหรับการตอบกลับทั้งหมดของโปรเจ็กต์ จากนั้นจึงเริ่มต้นอะแดปเตอร์ฐานข้อมูล โดยใช้ออบเจ็กต์การกำหนดค่าของเรา

ดังที่ฉันได้กล่าวไว้ก่อนหน้านี้ โปรเจ็กต์นี้ใช้ PostgreSQL หากคุณตัดสินใจที่จะใช้กลไกจัดการฐานข้อมูลอื่น เพียงเปลี่ยนอะแดปเตอร์ฐานข้อมูลในฟังก์ชัน db set คุณสามารถอ่านเพิ่มเติมเกี่ยวกับอะแดปเตอร์ฐานข้อมูลที่มีอยู่และเกี่ยวกับชั้นฐานข้อมูลได้ในเอกสารฐานข้อมูลของ PhalconPHP

สิ่งที่สามที่ควรทราบคือฉันลงทะเบียนตัวแปร $config ซึ่งใช้บริการ \Phalcon\Config แม้ว่าจะไม่ได้ใช้จริงในโปรเจ็กต์ตัวอย่างของเรา แต่ฉันก็ตัดสินใจรวมไว้ที่นี่เพราะเป็นหนึ่งในบริการที่ใช้กันมากที่สุด โปรเจ็กต์อื่นๆ อาจจำเป็นต้องเข้าถึงการกำหนดค่าเกือบทุกที่

สิ่งที่น่าสนใจประการสุดท้ายที่นี่คือวิธี setShared ที่แท้จริง การเรียกสิ่งนี้ทำให้บริการ "แชร์" ซึ่งหมายความว่าเริ่มทำตัวเหมือนซิงเกิล ตามเอกสาร: “เมื่อบริการได้รับการแก้ไขในครั้งแรก อินสแตนซ์เดียวกันของบริการจะถูกส่งคืนทุกครั้งที่ผู้บริโภคดึงบริการจากคอนเทนเนอร์”

กำลังกำหนดค่า routes.php …หรือไม่

ไฟล์รวมล่าสุดคือ routes.php เว้นว่างไว้ก่อน—เราจะเติมมันควบคู่ไปกับคอนโทรลเลอร์ของเรา

การใช้ RESTful Core

อะไรทำให้โครงการเว็บ RESTful ตาม Wikipedia มีสามส่วนหลักในแอปพลิเคชัน RESTful: - URL พื้นฐาน - ประเภทสื่ออินเทอร์เน็ตที่กำหนดองค์ประกอบข้อมูลการเปลี่ยนสถานะ - วิธี HTTP มาตรฐาน ( GET , POST , PUT , DELETE ) และรหัสตอบกลับ HTTP มาตรฐาน (200, 403, 400, 500 เป็นต้น)

ในโครงการของเรา URL พื้นฐานจะถูกวางลงในไฟล์ routes.php และจุดอื่นๆ ที่กล่าวถึงจะถูกอธิบายในตอนนี้

เราจะได้รับข้อมูลคำขอเป็น application/x-www-form-urlencoded และส่งข้อมูลการตอบกลับเป็น application/json แม้ว่าฉันจะไม่เชื่อว่าควรใช้ x-www-form-urlencoded ในแอปพลิเคชันจริง (เนื่องจากคุณจะต้องดิ้นรนเพื่อส่งโครงสร้างข้อมูลที่ซับซ้อนและอาร์เรย์ที่เชื่อมโยงด้วย x-www-form-urlencoded ) ฉันได้ ตัดสินใจที่จะใช้มาตรฐานนี้เพื่อประโยชน์ของความเรียบง่าย

หากคุณจำได้ เราได้ตั้งค่าส่วนหัว JSON การตอบสนองในไฟล์ DI แล้ว:

 $di->setShared( 'response', function () { $response = new \Phalcon\Http\Response(); $response->setContentType('application/json', 'utf-8'); return $response; } );

ตอนนี้ เราต้องตั้งค่ารหัสตอบกลับและรูปแบบการตอบกลับ บทช่วยสอนอย่างเป็นทางการแนะนำว่าเราสร้างการตอบสนอง JSON ในทุกวิธี แต่ฉันไม่คิดว่านี่เป็นความคิดที่ดี เป็นสากลมากขึ้นในการส่งคืนผลลัพธ์ของวิธีการควบคุมเป็นอาร์เรย์แล้วแปลงเป็นการตอบสนอง JSON มาตรฐาน คุณควรสร้างรหัสตอบกลับ HTTP ในที่เดียวภายในโปรเจ็กต์ด้วย เราจะทำสิ่งนี้ในไฟล์ index.php ของเรา

ในการทำเช่นนี้ เราจะใช้ความสามารถของ Phalcon ในการรันโค้ดก่อนและหลังการจัดการคำขอด้วย $app->before() และ $app->after() เราจะโทรกลับในเมธอด $app->after() เพื่อจุดประสงค์ของเรา:

 // Making the correct answer after executing $app->after( function () use ($app) { // Getting the return value of method $return = $app->getReturnedValue(); if (is_array($return)) { // Transforming arrays to JSON $app->response->setContent(json_encode($return)); } elseif (!strlen($return)) { // Successful response without any content $app->response->setStatusCode('204', 'No Content'); } else { // Unexpected response throw new Exception('Bad Response'); } // Sending response to the client $app->response->send(); }

ที่นี่เราได้รับผลตอบแทนและแปลงอาร์เรย์เป็น JSON หากทุกอย่างเรียบร้อยดี แต่ค่าส่งคืนว่างเปล่า (เช่น หากเราเพิ่มผู้ใช้ใหม่ได้สำเร็จ) เราจะให้รหัส HTTP 204 และไม่ส่งเนื้อหาใดๆ ในกรณีอื่นๆ ทั้งหมด เราใช้ข้อยกเว้น

การจัดการข้อยกเว้น

ลักษณะที่สำคัญที่สุดอย่างหนึ่งของแอปพลิเคชัน RESTful คือคำตอบที่ถูกต้องและให้ข้อมูล แอปพลิเคชันที่มีภาระงานสูงมักมีขนาดใหญ่ และข้อผิดพลาดประเภทต่างๆ สามารถเกิดขึ้นได้ทุกที่: ข้อผิดพลาดในการตรวจสอบความถูกต้อง ข้อผิดพลาดในการเข้าถึง ข้อผิดพลาดในการเชื่อมต่อ ข้อผิดพลาดที่ไม่คาดคิด ฯลฯ เราต้องการแปลงข้อผิดพลาดทั้งหมดให้เป็นรหัสตอบกลับ HTTP แบบรวมศูนย์ สามารถทำได้ง่ายด้วยความช่วยเหลือของข้อยกเว้น

ในโครงการของฉัน ฉันตัดสินใจใช้ข้อยกเว้นสองประเภท: มีข้อยกเว้น "ในเครื่อง" - คลาสพิเศษที่สืบทอดมาจากคลาส \RuntimeException แยกตามบริการ รุ่น อะแดปเตอร์ และอื่นๆ (ส่วนดังกล่าวช่วยในการรักษาแต่ละระดับ ของโมเดล MVC เป็นรุ่นแยกต่างหาก)- จากนั้นจะมี HttpExceptions ซึ่งสืบทอดมาจากคลาส AbstractHttpException ข้อยกเว้นเหล่านี้สอดคล้องกับรหัสตอบกลับ HTTP ดังนั้นชื่อของพวกเขาคือ Http400Exception , Http500Exception เป็นต้น

คลาส AbstractHttpException มีคุณสมบัติสามประการ: httpCode , httpMessage และ appError คุณสมบัติสองรายการแรกจะถูกแทนที่ในผู้สืบทอดและมีข้อมูลการตอบสนองพื้นฐาน เช่น httpCode: 400 และ httpMessage: Bad request คุณสมบัติ appError คืออาร์เรย์ของข้อมูลข้อผิดพลาดโดยละเอียด รวมถึงคำอธิบายข้อผิดพลาด

index.php เวอร์ชันสุดท้ายของเราจะตรวจจับข้อยกเว้นสามประเภท: AbstractHttpExceptions ตามที่อธิบายไว้ข้างต้น ข้อยกเว้นคำขอ Phalcon ซึ่งอาจเกิดขึ้นขณะแยกวิเคราะห์คำขอ และข้อยกเว้นอื่นๆ ที่ไม่คาดคิดทั้งหมด ทั้งหมดจะถูกแปลงเป็นรูปแบบ JSON ที่สวยงามและส่งไปยังไคลเอนต์ผ่านคลาส Phalcon Response มาตรฐาน:

 <?php use App\Controllers\AbstractHttpException; try { // Loading Configs $config = require(__DIR__ . '/../app/config/config.php'); // Autoloading classes require __DIR__ . '/../app/config/loader.php'; // Initializing DI container /** @var \Phalcon\DI\FactoryDefault $di */ $di = require __DIR__ . '/../app/config/di.php'; // Initializing application $app = new \Phalcon\Mvc\Micro(); // Setting DI container $app->setDI($di); // Setting up routing require __DIR__ . '/../app/config/routes.php'; // Making the correct answer after executing $app->after( // After Code ); // Processing request $app->handle(); } catch (AbstractHttpException $e) { $response = $app->response; $response->setStatusCode($e->getCode(), $e->getMessage()); $response->setJsonContent($e->getAppError()); $response->send(); } catch (\Phalcon\Http\Request\Exception $e) { $app->response->setStatusCode(400, 'Bad request') ->setJsonContent([ AbstractHttpException::KEY_CODE => 400, AbstractHttpException::KEY_MESSAGE => 'Bad request' ]) ->send(); } catch (\Exception $e) { // Standard error format $result = [ AbstractHttpException::KEY_CODE => 500, AbstractHttpException::KEY_MESSAGE => 'Some error occurred on the server.' ]; // Sending error response $app->response->setStatusCode(500, 'Internal Server Error') ->setJsonContent($result) ->send(); }

การสร้างแบบจำลองด้วย Phalcon Dev Tools

หากคุณใช้ IDE ร่วมสมัย คุณอาจเคยชินกับการเน้นสีและการเติมโค้ดให้สมบูรณ์ ในทำนองเดียวกัน ในเฟรมเวิร์ก PHP ทั่วไป คุณสามารถรวมโฟลเดอร์ที่มีเฟรมเวิร์กเพื่อไปที่การประกาศฟังก์ชันได้ในคลิกเดียว เนื่องจาก Phalcon เป็นส่วนขยาย เราจึงไม่ได้รับตัวเลือกนี้โดยอัตโนมัติ โชคดีที่มีเครื่องมือที่อุดช่องว่างนี้เรียกว่า “Phalcon Dev Tools” ซึ่งสามารถติดตั้งผ่าน Composer ได้ (หากคุณยังไม่รู้ว่ามันคืออะไร ถึงเวลาทำความรู้จักกับ Package Manager ที่น่าทึ่งนี้แล้ว) Phalcon Dev Tools ประกอบด้วยโค้ด stubs สำหรับคลาสและฟังก์ชันทั้งหมดใน Phalcon และจัดเตรียมตัวสร้างโค้ดบางตัวที่มีทั้งเวอร์ชันคอนโซลและ GUI ซึ่งบันทึกไว้ในเว็บไซต์ PhalconPHP เครื่องมือเหล่านี้สามารถช่วยในการสร้างทุกส่วนของรูปแบบ MVC แต่เราจะครอบคลุมเฉพาะการสร้างแบบจำลองเท่านั้น

ตกลง มาติดตั้ง Phalcon Dev Tools ผ่าน Composer กันเถอะ ไฟล์ composer.json ของเราจะมีลักษณะดังนี้:

 { "require": { "php": ">=5.6.0", "ext-phalcon": ">=3", "ext-pgsql": "*" }, "require-dev": { "phalcon/devtools": "3.*.*@dev" } }

อย่างที่คุณเห็น เราต้องการ PHP 5.6, Phalcon 3 และส่วนขยาย pgsql (ซึ่งคุณสามารถเปลี่ยนเป็นส่วนขยายฐานข้อมูลหรือยกเว้นทั้งหมดได้)

ตรวจสอบให้แน่ใจว่าคุณมีเวอร์ชันส่วนขยาย PHP, Phalcon และ DB ที่ถูกต้อง และเรียกใช้ผู้แต่ง:

 $ composer install

ขั้นตอนต่อไปคือการสร้างฐานข้อมูลของเรา มันง่ายมากและประกอบด้วยเพียงหนึ่งตาราง users . แม้ว่าฉันได้รวมไฟล์ pg_dump ไว้ในโปรเจ็กต์แล้ว แต่นี่คือ SQL ในภาษาถิ่นของ PostgreSQL:

 CREATE DATABASE articledemo; CREATE TABLE public.users ( id INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('users_id_seq'::regclass), first_name CHARACTER VARYING(255), last_name CHARACTER VARYING(255), pass CHARACTER VARYING(255), login CHARACTER VARYING(255) NOT NULL );

เมื่อสร้างฐานข้อมูลแล้ว เราสามารถดำเนินการตามขั้นตอนการสร้างแบบจำลองได้ Phalcon Dev Tools ใช้โฟลเดอร์ .phalcon ว่างเพื่อตรวจสอบว่าแอปพลิเคชันนั้นเป็นโปรเจ็กต์ Phalcon หรือไม่ ดังนั้น คุณจะต้องสร้างโฟลเดอร์ว่างนี้ในรูทของโปรเจ็กต์ของคุณ นอกจากนี้ยังใช้การตั้งค่าบางอย่างจากไฟล์การกำหนดค่าที่เราสร้างขึ้น ซึ่งก็คือตัวแปรทั้งหมดที่เก็บอยู่ภายใต้ส่วน application และ adapter จากส่วน database ในการสร้างโมเดลของเรา เราต้องรันคำสั่งต่อไปนี้จากโฟลเดอร์รูทของโปรเจ็กต์:

 $ php vendor/phalcon/devtools/phalcon.php model users --namespace="App\Models" --get-set

หากทำตามขั้นตอนก่อนหน้านี้ทั้งหมดอย่างถูกต้อง คุณจะได้รับไฟล์โมเดลการทำงาน Users.php ในโฟลเดอร์ models ของคุณ ซึ่งได้วางไว้ในเนมสเปซที่มี getters และ setters ตามที่บรรทัดคำสั่งระบุไว้ ถัดไปคือตัวควบคุม

ตัวควบคุมและการกำหนดเส้นทาง

เนื่องจากแอปพลิเคชันของเรามีเฉพาะผู้ใช้ CRUD (สร้าง อ่าน อัปเดต และลบ) เราจะสร้างตัวควบคุมเพียงตัวเดียว นั่นคือตัวควบคุม Users ที่มีการดำเนินการต่อไปนี้:

  • เพิ่มผู้ใช้
  • แสดงรายการผู้ใช้
  • อัปเดตผู้ใช้
  • ลบผู้ใช้

ในขณะที่สามารถสร้างตัวควบคุมได้ด้วยความช่วยเหลือของ Phalcon Dev Tools เราจะดำเนินการด้วยตนเองและใช้งาน AbstractController และลูกของมัน UsersController

การสร้าง AbstractController เป็นการตัดสินใจที่ดีสำหรับ Phalcon เนื่องจากเราสามารถวางคลาสที่จำเป็นทั้งหมด ซึ่งเราจะได้จากการแทรกการพึ่งพาลงในบล็อก PHPDoc สิ่งนี้จะช่วยด้วยฟังก์ชันเติมข้อความอัตโนมัติ IDE นอกจากนี้เรายังสามารถตั้งโปรแกรมในค่าคงที่ข้อผิดพลาดบางอย่างที่เหมือนกันกับตัวควบคุมทั้งหมดที่เป็นไปได้

สำหรับตอนนี้ abstract controller ของเราจะมีลักษณะดังนี้:

 <?php namespace App\Controllers; /** * Class AbstractController * * @property \Phalcon\Http\Request $request * @property \Phalcon\Http\Response $htmlResponse * @property \Phalcon\Db\Adapter\Pdo\Postgresql $db * @property \Phalcon\Config $config * @property \App\Services\UsersService $usersService * @property \App\Models\Users $user */ abstract class AbstractController extends \Phalcon\DI\Injectable { /** * Route not found. HTTP 404 Error */ const ERROR_NOT_FOUND = 1; /** * Invalid Request. HTTP 400 Error. */ const ERROR_INVALID_REQUEST = 2; }

เป็นเพียงคลาสฉีด Phalcon ธรรมดาตามที่ระบุโดยไวยากรณ์ส่วน extends ไม่มีอะไรเพิ่มเติม ต่อไป มาสร้างโครงร่าง UsersController :

 <?php namespace App\Controllers; /** * Operations with Users: CRUD */ class UsersController extends AbstractController { /** * Adding user */ public function addAction() { } /** * Returns user list * * @return array */ public function getUserListAction() { } /** * Updating existing user * * @param string $userId */ public function updateUserAction($userId) { } /** * Delete an existing user * * @param string $userId */ public function deleteUserAction($userId) { } }

ในขณะนี้ เป็นเพียงคลาสที่มีการดำเนินการว่างเปล่า ซึ่งจะเก็บคำขอ HTTP ที่สอดคล้องกันในที่สุด

ตอนนี้ได้เวลากรอกไฟล์ routes.php ในไมโครแอปพลิเคชัน Phalcon เราสร้างคอลเล็กชันหนึ่งชุดสำหรับคอนโทรลเลอร์แต่ละตัว และเพิ่มคำขอที่ได้รับการจัดการทั้งหมดเป็นเมธอด get , post , put , delete ซึ่งรับรูปแบบเส้นทางและฟังก์ชันการดำเนินการเป็นอาร์กิวเมนต์ โปรดทราบว่าฟังก์ชันที่ดำเนินการควรเป็นฟังก์ชันที่ไม่ระบุตัวตนหรือชื่อเมธอดของคอนโทรลเลอร์ นี่คือลักษณะของไฟล์ routes.php ของเรา:

 <?php $usersCollection = new \Phalcon\Mvc\Micro\Collection(); $usersCollection->setHandler('\App\Controllers\UsersController', true); $usersCollection->setPrefix('/user'); $usersCollection->post('/add', 'addAction'); $usersCollection->get('/list', 'getUserListAction'); $usersCollection->put('/{userId:[1-9][0-9]*}', 'updateUserAction'); $usersCollection->delete('/{userId:[1-9][0-9]*}', 'deleteUserAction'); $app->mount($usersCollection); // not found URLs $app->notFound( function () use ($app) { $exception = new \App\Controllers\HttpExceptions\Http404Exception( _('URI not found or error in request.'), \App\Controllers\AbstractController::ERROR_NOT_FOUND, new \Exception('URI not found: ' . $app->request->getMethod() . ' ' . $app->request->getURI()) ); throw $exception; } );

เรายังตั้งค่าตัวควบคุมการจัดการและคำนำหน้า URI สำหรับตัวอย่างของเรา URI จะมีลักษณะดังนี้ http://article.dev/user/add และต้องเป็นคำขอ post หากเราต้องการเปลี่ยนข้อมูลผู้ใช้ URI จะต้องเป็นคำขอ put และจะมีลักษณะเหมือน http://article.dev/user/12 เพื่อเปลี่ยนข้อมูลสำหรับผู้ใช้ที่มี ID 12 นอกจากนี้เรายังกำหนดตัวจัดการ URL ที่ไม่พบ ซึ่งแสดงข้อผิดพลาด สำหรับข้อมูลเพิ่มเติม โปรดดูเอกสารประกอบของ PhalconPHP สำหรับเส้นทางในแอปพลิเคชันแบบเต็ม และเส้นทางในแอปพลิเคชันขนาดเล็ก

ไปที่เนื้อหาของคอนโทรลเลอร์และโดยเฉพาะอย่างยิ่งวิธีการ addAction (ส่วนอื่น ๆ ทั้งหมดคล้ายกัน คุณสามารถเห็นได้ในรหัสแอปพลิเคชัน) วิธีการควบคุมทำห้าสิ่ง:

  1. รับและตรวจสอบพารามิเตอร์คำขอ
  2. จัดเตรียมข้อมูลสำหรับวิธีบริการ
  3. เรียกวิธีการบริการ
  4. จัดการข้อยกเว้น
  5. ส่งการตอบกลับ

มาดูแต่ละขั้นตอนกัน โดยเริ่มจากการตรวจสอบความถูกต้อง แม้ว่า Phalcon จะมีองค์ประกอบการตรวจสอบที่มีประสิทธิภาพ แต่ก็ควรตรวจสอบข้อมูลด้วยวิธีแบบเก่าในกรณีนี้มากกว่า ดังนั้นบล็อกการตรวจสอบความถูกต้องของเราจะมีลักษณะดังนี้:

 $errors = []; $data = []; $data['login'] = $this->request->getPost('login'); if (!is_string($data['login']) || !preg_match('/^[A-z0-9_-]{3,16}$/', $data['login'])) { $errors['login'] = 'Login must consist of 3-16 latin symbols, numbers or \'-\' and \'_\' symbols'; }

ที่นี่เราตรวจสอบว่าพารามิเตอร์ post เป็นสตริงที่ตรงกับนิพจน์ทั่วไปหรือไม่ ค่าทั้งหมดจะถูกใส่ลงในอาร์เรย์ $data ซึ่งจะถูกส่งต่อไปยังคลาส UsersService ข้อผิดพลาดทั้งหมดจะถูกใส่ลงในอาร์เรย์ $errors ซึ่งจะถูกเพิ่มลงในอาร์เรย์รายละเอียดข้อผิดพลาดภายใน Http400Exception ซึ่งจะถูกแปลงเป็นการตอบกลับโดยละเอียดใน index.php :

นี่คือโค้ดวิธี addAction แบบเต็มพร้อมการตรวจสอบทั้งหมด ซึ่งรวมถึงการโทรไปยังเมธอด createUser ใน UsersService (ซึ่งเรายังไม่ได้สร้าง):

 public function addAction() { /** Init Block **/ $errors = []; $data = []; /** End Init Block **/ /** Validation Block **/ $data['login'] = $this->request->getPost('login'); if (!is_string($data['login']) || !preg_match('/^[A-z0-9_-]{3,16}$/', $data['login'])) { $errors['login'] = 'Login must consist of 3-16 latin symbols, numbers or \'-\' and \'_\' symbols'; } $data['password'] = $this->request->getPost('password'); if (!is_string($data['password']) || !preg_match('/^[A-z0-9_-]{6,18}$/', $data['password'])) { $errors['password'] = 'Password must consist of 6-18 latin symbols, numbers or \'-\' and \'_\' symbols'; } $data['first_name'] = $this->request->getPost('first_name'); if ((!empty($data['first_name'])) && (!is_string($data['first_name']))) { $errors['first_name'] = 'String expected'; } $data['last_name'] = $this->request->getPost('last_name'); if ((!empty($data['last_name'])) && (!is_string($data['last_name']))) { $errors['last_name'] = 'String expected'; } if ($errors) { $exception = new Http400Exception(_('Input parameters validation error'), self::ERROR_INVALID_REQUEST); throw $exception->addErrorDetails($errors); } /** End Validation Block **/ /** Passing to business logic and preparing the response **/ try { $this->usersService->createUser($data); } catch (ServiceException $e) { switch ($e->getCode()) { case AbstractService::ERROR_ALREADY_EXISTS: case UsersService::ERROR_UNABLE_CREATE_USER: throw new Http422Exception($e->getMessage(), $e->getCode(), $e); default: throw new Http500Exception(_('Internal Server Error'), $e->getCode(), $e); } } /** End Passing to business logic and preparing the response **/ }

อย่างที่คุณเห็น เราจัดการข้อยกเว้นที่ทราบสองข้อในส่วนสุดท้ายนั้น: user already exists และ unable to create user เนื่องจากปัญหาภายในบางอย่าง เช่น ข้อผิดพลาดในการเชื่อมต่อฐานข้อมูล โดยค่าเริ่มต้น ข้อยกเว้นที่ไม่รู้จักจะถูกส่งออกเป็น HTTP 500 (ข้อผิดพลาดของเซิร์ฟเวอร์ภายใน) แม้ว่าเราจะไม่ให้รายละเอียดใดๆ แก่ผู้ใช้ แต่ขอแนะนำอย่างยิ่งให้เก็บรายละเอียดข้อผิดพลาดทั้งหมด (รวมถึงการติดตาม) ไว้ในบันทึก

และโปรดอย่าลืม use คลาสที่จำเป็นทั้งหมดที่ยืมมาจากเนมสเปซอื่น:

 use App\Controllers\HttpExceptions\Http400Exception; use App\Controllers\HttpExceptions\Http422Exception; use App\Controllers\HttpExceptions\Http500Exception; use App\Services\AbstractService; use App\Services\ServiceException; use App\Services\UsersService;

ตรรกะทางธุรกิจ

ส่วนสุดท้ายในการสร้างคือตรรกะทางธุรกิจ เช่นเดียวกับตัวควบคุม เราจะสร้างคลาสบริการที่เป็นนามธรรม:

 <?php namespace App\Services; /** * Class AbstractService * * @property \Phalcon\Db\Adapter\Pdo\Postgresql $db * @property \Phalcon\Config $config */ abstract class AbstractService extends \Phalcon\DI\Injectable { /** * Invalid parameters anywhere */ const ERROR_INVALID_PARAMETERS = 10001; /** * Record already exists */ const ERROR_ALREADY_EXISTS = 10002; }

แนวคิดนี้เหมือนกับในบล็อกของคอนโทรลเลอร์ทั้งหมด ดังนั้นฉันจะไม่แสดงความคิดเห็น นี่คือโครงร่างของคลาส UsersService ของเรา:

 <?php namespace App\Services; use App\Models\Users; /** * business logic for users * * Class UsersService */ class UsersService extends AbstractService { /** Unable to create user */ const ERROR_UNABLE_CREATE_USER = 11001; /** * Creating a new user * * @param array $userData */ public function createUser(array $userData) { } }

และเมธอด createUser เอง:

 public function createUser(array $userData) { try { $user = new Users(); $result = $user->setLogin($userData['login']) ->setPass(password_hash($userData['password'], PASSWORD_DEFAULT)) ->setFirstName($userData['first_name']) ->setLastName($userData['last_name']) ->create(); if (!$result) { throw new ServiceException('Unable to create user', self::ERROR_UNABLE_CREATE_USER); } } catch (\PDOException $e) { if ($e->getCode() == 23505) { throw new ServiceException('User already exists', self::ERROR_ALREADY_EXISTS, $e); } else { throw new ServiceException($e->getMessage(), $e->getCode(), $e); } } }

วิธีนี้ง่ายที่สุดเท่าที่จะทำได้ เราเพิ่งสร้างอ็อบเจ็กต์โมเดลใหม่ เรียก setters (ซึ่งส่งคืนอ็อบเจ็กต์เอง ซึ่งช่วยให้เราสร้าง call chain ได้) และโยน ServiceException ในกรณีที่เกิดข้อผิดพลาด แค่นั้นแหละ! ตอนนี้เราสามารถดำเนินการทดสอบได้

การทดสอบ

ทีนี้มาดูผลลัพธ์โดยใช้บุรุษไปรษณีย์กัน มาทดสอบข้อมูลถังขยะกันก่อน:

บุรุษไปรษณีย์ที่มีข้อมูลที่ไม่ถูกต้อง

ขอ:

 POST http://article.dev/user/add login:1 password:1 first_name:Name last_name:Sourname

ตอบกลับ (400: คำขอไม่ถูกต้อง):

 { "error": 2, "error_description": "Input parameters validation error", "details": { "login": "Login must consist of 3-16 latin symbols, numbers or '-' and '_' symbols", "password": "Password must consist of 6-18 latin symbols, numbers or '-' and '_' symbols" } }

ที่เช็คเอาท์ ตอนนี้สำหรับข้อมูลที่ถูกต้อง:

บุรุษไปรษณีย์ที่มีข้อมูลที่ถูกต้อง

ขอ:

 POST http://article.dev/user/add login:user4 password:password4 first_name:Name last_name:Sourname

ตอบกลับ (204):

No content, which is what we expected. Now let's make sure it worked and get the full user list (which we didn't describe in the article, but you can see it in the application example):

Request:

 GET http://article.dev/user/list

Response (200 OK):

 [ { "id": 1, "login": "user4", "first_name": "Name", "last_name": "Sourname" } ]

Well, it works!

Logging and Caching

It's hard to imagine a high-load application without logging and caching, and Phalcon provides very seductive classes for it. But I'm writing an article here, not a book; I've added logging and caching to the sample application, but I've placed this code into another branch called logging-and-cache so you can easily look at it and see the difference in the code. Just like the other Phalcon features, these two are well-documented: Logging and Caching.

ข้อเสีย

As you can see, Phalcon is really cool, but like other frameworks, it has its disadvantages, the first of which is the same as its main advantage—it's a compiled C extension. That's why there is no way for you to change its code easily. Well, if you know C, you can try to understand its code and make some changes, run make and get your own modification of Phalcon, but it is much more complicated than making some tweaks in PHP code. So, generally, if you find a bug inside Phalcon, it won't be so easy to fix.

This is partially solved in Phalcon 2 and Phalcon 3, which let you write extensions to Phalcon in Zephir. Zephir is a programming language designed to ease the creation and maintainability of extensions for PHP with a focus on type and memory safety. Its syntax is very close to PHP and Zephir code is compiled into shared libraries, same as the PHP extension. So, if you want to enhance Phalcon, now you can.

The second disadvantage is the free framework structure. While Symfony makes developers use a firm project structure, Phalcon has very few strict rules; developers can create any structure they like, though there is a structure that is recommended by its authors. This isn't a critical disadvantage, but some people may consider it too raw when you write the paths to all the directories in a bootstrap file manually.

PhalconPHP: Not Just For High-load Apps

I hope you've enjoyed this brief overview of PhalconPHP's killing features and the accompanying simple example of a Phalcon project. Obviously, I didn't cover all the possibilities of this framework since it's impossible to describe all of them in one article, but fortunately Phalcon has brilliantly detailed documentation with seven marvelous tutorials which help you understand almost everything about Phalcon.

You've now got a brand new way to create high load applications easily, and you'll find, if you like Phalcon, it can be a good choice for other types of applications too.