วิธีใช้ Composer จัดการ package ในโปรเจกต์ PHP

Composer เป็นตัวจัดการ dependency ของ PHP อ่านรายการ package จาก composer.json โหลดจาก Packagist มาไว้ใน vendor และจดเวอร์ชันที่ลงจริงไว้ใน composer.lock คำสั่งที่ใช้เกือบทุกวันคือ require, install, update, remove และ outdated ส่วนตอน deploy ใช้ composer install --no-dev -o

เผยแพร่
เวลาอ่าน
6 นาที
ในโพสต์นี้ 12 หัวข้อ
  1. Composer เป็นตัวจัดการ dependency ของ PHP
  2. ติดตั้ง Composer
  3. ไฟล์สามอย่างที่ Composer ดูแล
  4. เลขเวอร์ชันใน composer.json
  5. เริ่มโปรเจกต์ใหม่
  6. เพิ่มและลบ package
  7. install กับ update ต่างกันที่ lock file
  8. ตอน deploy ขึ้น production
  9. ดูว่ามีอะไรต้องอัปเดตและใครดึง package มา
  10. เช็คช่องโหว่ด้วย composer audit
  11. คำสั่งที่ไม่ได้ใช้ทุกวันแต่ควรรู้
  12. ปัญหาที่อาจเจอตอนใช้งานจริง

ก่อนมี Composer ถ้าอยากใช้ library อย่าง PHPMailer เราก็ต้องไปโหลด zip มาแตกไว้ในโปรเจกต์ แล้ว require_once ไฟล์ของมันเอง พอ library นั้นต้องใช้ library อื่นต่อ ก็ต้องไปหามาเพิ่มอีก และวันที่อยากอัปเดตก็ต้องทำแบบเดิมซ้ำทุกตัว Composer ทำงานส่วนนี้ให้ทั้งหมด

Composer เป็นตัวจัดการ dependency ของ PHP

เอกสารของ Composer เรียกตัวเองว่า dependency manager คือเราประกาศว่าโปรเจกต์ต้องใช้อะไร แล้ว Composer หาเวอร์ชันที่เข้ากันได้ทั้งหมดมาติดตั้งให้ รวมถึง package ที่ package เหล่านั้นใช้ต่ออีกทอดด้วย ทุกอย่างลงไว้ในโฟลเดอร์ vendor ของโปรเจกต์นั้น ไม่ได้ลงทั้งเครื่องแบบ apt ทำให้สองโปรเจกต์บนเครื่องเดียวกันใช้ Laravel คนละเวอร์ชันได้

package ส่วนใหญ่มาจาก Packagist ซึ่งเป็นที่รวม package สาธารณะของ PHP ตอนนี้มีมากกว่า 470,000 package แนวคิดเดียวกับ npm ฝั่ง JavaScript ซึ่ง Composer ก็บอกว่าได้แรงบันดาลใจมาจาก npm กับ bundler ของ Ruby

ติดตั้ง Composer

Composer รุ่นล่าสุดต้องใช้ PHP 7.2.5 ขึ้นไป

  • Windows โหลด Composer-Setup.exe มาติดตั้ง ตัวติดตั้งจะถามหา php.exe ถ้าใช้ XAMPP ก็ชี้ไปที่ C:\xampp\php\php.exe แล้วตั้ง PATH ให้เอง ปิด terminal แล้วเปิดใหม่ก่อนลองเรียก composer
  • macOS ใช้ Homebrew ติดตั้งด้วย brew install composer
  • Linux และเซิร์ฟเวอร์ ใช้ตัวติดตั้งตามขั้นตอนในหน้า download แล้วย้าย composer.phar ไปไว้ที่ /usr/local/bin/composer

Laragon และ Laravel Herd มี Composer มาให้ในตัวแล้ว เช็คว่าใช้ได้ด้วย composer --version

ไฟล์สามอย่างที่ Composer ดูแล

ไฟล์ ทำหน้าที่อะไร commit ขึ้น git ไหม
composer.json รายการ package ที่เราขอ พร้อมช่วงเวอร์ชันที่รับได้ commit
composer.lock เวอร์ชันที่ลงจริงของทุก package รวมตัวที่ลงตามมา commit
vendor/ โค้ดของ package ทั้งหมด ไม่ commit ใส่ใน .gitignore

composer.lock คือไฟล์ที่ทำให้ทุกเครื่องได้เวอร์ชันเดียวกัน เพื่อนในทีมที่ clone โปรเจกต์ไป และเซิร์ฟเวอร์ที่ deploy จะได้ package ทุกตัวตรงกับเครื่องเราทุกตัว ส่วน vendor สร้างใหม่จาก lock file ได้ทุกเมื่อ จึงไม่ต้องเก็บใน git

Composer ยังสร้าง autoloader ไว้ที่ vendor/autoload.php ด้วย โค้ดของเรา require ไฟล์นี้ไฟล์เดียวก็เรียกใช้ class ของทุก package ได้ทันที Laravel ก็ทำแบบนี้ไว้ใน public/index.php อยู่แล้ว

เลขเวอร์ชันใน composer.json

ใน composer.json เราไม่ได้ล็อกเวอร์ชันตายตัว แต่บอกเป็นช่วงที่รับได้ เครื่องหมายที่เจอบ่อยมีสองตัว (เอกสารเรื่องเวอร์ชัน)

เขียนว่า รับเวอร์ชัน ใช้เมื่อ
^13.0 ตั้งแต่ 13.0 แต่ไม่ถึง 14.0 ค่าปกติ รับ minor กับ patch ไม่รับ major ที่อาจมี breaking change
^0.3 ตั้งแต่ 0.3.0 แต่ไม่ถึง 0.4.0 package ที่ยังไม่ถึง 1.0 ขยับ minor ก็อาจพังได้
~1.2.3 ตั้งแต่ 1.2.3 แต่ไม่ถึง 1.3.0 อยากรับแค่ patch
1.0.2 1.0.2 ตัวเดียว ต้องล็อกไว้จริง ๆ เช่นรอแพตช์ของ package

composer require ใส่ ^ ให้เองตามเวอร์ชันล่าสุดที่ลงได้ ส่วนใหญ่เราจึงไม่ต้องเขียนเอง

เริ่มโปรเจกต์ใหม่

composer create-project laravel/laravel shop

create-project สร้างโปรเจกต์ใหม่จาก package ต้นแบบ แล้วลง dependency ให้ครบในคำสั่งเดียว ถ้าเป็นโปรเจกต์ PHP ธรรมดาที่ยังไม่มี composer.json ก็ใช้ composer init ให้ Composer ถามทีละข้อแล้วสร้างไฟล์ให้

เพิ่มและลบ package

composer require phpoffice/phpspreadsheet
composer require --dev laravel/pint
composer remove phpoffice/phpspreadsheet
  • require เพิ่ม package ลงใน composer.json ลงเวอร์ชันล่าสุดที่เข้ากับโปรเจกต์ได้ แล้วอัปเดต lock file ให้ ระบุเวอร์ชันเองได้ด้วย composer require "vendor/package:^2.0"
  • --dev ใส่ไว้ใน require-dev สำหรับของที่ใช้ตอนพัฒนาเท่านั้น เช่นเครื่องมือ test และ code style ซึ่ง production ไม่ต้องลง
  • remove เอาออกจาก composer.json แล้วลบออกจาก vendor และ lock file

install กับ update ต่างกันที่ lock file

สองคำสั่งนี้ชื่อคล้ายกัน แต่ใช้คนละจังหวะ

คำสั่ง ทำอะไร ใช้ตอนไหน
composer install ลงตาม composer.lock ทุกตัว ไม่เปลี่ยนเวอร์ชัน หลัง clone, หลัง git pull, ตอน deploy
composer update หาเวอร์ชันใหม่ที่ยังอยู่ในช่วงของ composer.json แล้วเขียน lock file ใหม่ ตอนตั้งใจอัปเดต package
composer update laravel/framework
composer update laravel/framework -W
composer update --dry-run
  • ใส่ชื่อ package หลัง update เพื่ออัปเดตแค่ตัวนั้น ตัวอื่นใน lock file ไม่ขยับ
  • -W (--with-all-dependencies) ให้ขยับ dependency ของตัวนั้นด้วย ใช้เมื่อ Composer บอกว่าอัปเดตไม่ได้เพราะ dependency ล็อกเวอร์ชันไว้
  • --dry-run ดูก่อนว่าจะเปลี่ยนอะไรบ้าง โดยยังไม่ลงจริง

ถ้าเพื่อนในทีมรัน update แล้ว commit lock file มา เราแค่รัน composer install ก็ได้เวอร์ชันเดียวกัน ถ้าลืมบ่อย ลองตั้ง git hook ให้รัน composer install เองหลัง git pull ได้

update คือจังหวะที่ package เวอร์ชันใหม่เข้ามาในโปรเจกต์ Composer 2.11 ขึ้นไปตั้งให้รอเวอร์ชันที่เพิ่งออกสักพักก่อนติดตั้ง ได้ เผื่อเวอร์ชันนั้นเป็นของปลอมจากบัญชีที่โดนยึด

ตอน deploy ขึ้น production

composer install --no-dev --optimize-autoloader --no-interaction
  • --no-dev ไม่ลง package ใน require-dev เครื่องมือ test และ debug จะไม่ขึ้นไปอยู่บนเซิร์ฟเวอร์
  • --optimize-autoloader (-o) สร้าง classmap ให้ autoloader หา class ได้เร็วขึ้น เอกสารของ Composer แนะนำให้ใช้บน production
  • --no-interaction (-n) ไม่ถามอะไรระหว่างทาง เหมาะกับ script deploy และ CI

ห้ามรัน composer update บนเซิร์ฟเวอร์ เพราะจะได้เวอร์ชันที่ไม่เคยทดสอบบนเครื่องเรา ถ้าอยากเห็นว่าคำสั่งนี้อยู่ตรงไหนในขั้น deploy ทั้งหมด ลองอ่านลำดับขั้น deploy Laravel ได้ครับ

ดูว่ามีอะไรต้องอัปเดตและใครดึง package มา

composer outdated -D
composer show laravel/framework
composer why guzzlehttp/guzzle
composer why-not php 8.5
  • outdated แสดง package ที่มีเวอร์ชันใหม่ -D ดูเฉพาะตัวที่เราใส่เองใน composer.json ไม่รวมตัวที่ลงตามมา --major-only, --minor-only, --patch-only กรองตามระดับได้
  • show ดูรายละเอียดของ package ที่ลงอยู่ ใส่ --tree จะเห็นว่าแต่ละตัวใช้อะไรต่อ
  • why บอกว่า package ไหนดึงตัวนี้เข้ามา เจอ package แปลก ๆ ใน lock file ก็ใช้คำสั่งนี้
  • why-not บอกว่าอะไรทำให้ขยับไปเวอร์ชันนั้นไม่ได้ ใช้บ่อยตอนเตรียมอัปเกรด PHP

เช็คช่องโหว่ด้วย composer audit

composer audit

audit เทียบ package ที่ลงอยู่กับฐานข้อมูลช่องโหว่ แล้วบอกว่าตัวไหนมี advisory พร้อมระดับความรุนแรง คำสั่งจบด้วย error เมื่อเจอปัญหา จึงใส่ใน CI ได้เลย Composer รุ่นใหม่รัน audit ให้เองหลัง require และ update ด้วย ถ้าไม่อยากคอยรันเอง Dependabot ช่วยเปิด PR แพตช์ให้ได้

คำสั่งที่ไม่ได้ใช้ทุกวันแต่ควรรู้

  • composer dump-autoload สร้าง autoloader ใหม่ ใช้หลังเพิ่ม namespace ใน autoload ของ composer.json หรือเพิ่ม helper file
  • composer run-script หรือ composer run รันคำสั่งที่ตั้งไว้ใน scripts ของ composer.json โปรเจกต์ Laravel ใหม่มี composer run dev ที่เปิด server, queue และ Vite พร้อมกัน
  • composer self-update อัปเดตตัว Composer เอง ถ้ารุ่นใหม่มีปัญหา ถอยกลับด้วย composer self-update --rollback
  • composer diagnose ตรวจปัญหาที่เจอบ่อย เช่นต่อ Packagist ไม่ได้ หรือตั้งค่า PHP ไม่ครบ
  • composer global require ลงเครื่องมือไว้ใช้ทั้งเครื่อง เช่น composer global require laravel/installer แล้วเรียก laravel new ได้จากทุกโฟลเดอร์

ปัญหาที่อาจเจอตอนใช้งานจริง

Your requirements could not be resolved แปลว่า Composer หาเวอร์ชันที่เข้ากันได้ทุกตัวไม่เจอ อ่านข้อความต่อจากนั้นจะบอกว่าตัวไหนติดกับตัวไหน บ่อยครั้งเป็นเรื่องเวอร์ชัน PHP บนเครื่องต่ำกว่าที่ package ต้องการ เช่น XAMPP ที่ยังเป็น PHP 8.1 แต่ Laravel 13 ต้องใช้ 8.3 ขึ้นไป

ขาด PHP extension เช่น ext-zip, ext-gd หรือ ext-intl บน XAMPP เปิดได้ด้วยการเอา ; หน้าบรรทัด extension= ใน php.ini ออก แล้วเปิด terminal ใหม่ composer check-platform-reqs จะบอกว่าเครื่องนี้ขาดอะไรที่ package ในโปรเจกต์ต้องใช้

--ignore-platform-reqs ทำให้ติดตั้งผ่านได้ก็จริง แต่ package ที่ต้องใช้ extension นั้นจะไปพังตอนรันแทน ควรใช้เฉพาะตอนที่รู้ว่าเครื่องที่รันจริงมี extension ครบ เช่นลง package บนเครื่องเราแต่ไปรันใน Docker

หน่วยความจำไม่พอ บนเซิร์ฟเวอร์เล็กหรือ shared hosting composer update อาจหยุดด้วย error เรื่อง memory ทางที่ดีคือรัน update บนเครื่องเรา แล้วให้เซิร์ฟเวอร์รันแค่ install ซึ่งใช้หน่วยความจำน้อยกว่ามาก ถ้าจำเป็นต้องรันจริง ๆ ปลดล็อกชั่วคราวได้ด้วย COMPOSER_MEMORY_LIMIT=-1

คำสั่งทั้งหมดพร้อมตัวเลือกครบทุกตัวอยู่ในเอกสาร command-line ของ Composer ครับ

อ่านต่อ

ถูกอ้างถึงใน

ล่าสุด

ดูทั้งหมด →