สุดยอดคู่มือสำหรับการ Transpiling PHP Code

เผยแพร่แล้ว: 2021-09-22

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

ในสถานการณ์เหล่านี้ เราอาจเลิกหวังที่จะใช้โค้ด PHP ล่าสุด แต่มีทางเลือกอื่นที่ดีกว่า: เรายังคงสามารถเขียนซอร์สโค้ดของเราด้วย PHP 8.0 และแปลงเป็น PHP เวอร์ชันก่อนหน้า แม้กระทั่ง PHP 7.1

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

Transpiling คืออะไร?

Transpiling แปลงซอร์สโค้ดจากภาษาการเขียนโปรแกรมเป็นซอร์สโค้ดที่เทียบเท่ากับภาษาโปรแกรมเดียวกันหรือภาษาอื่น

Transpiling ไม่ใช่แนวคิดใหม่ในการพัฒนาเว็บ: นักพัฒนาฝั่งไคลเอ็นต์จะค่อนข้างคุ้นเคยกับ Babel ซึ่งเป็นทรานสไพเลอร์สำหรับโค้ด JavaScript

Babel แปลงโค้ด JavaScript จากเวอร์ชัน ECMAScript 2015+ ที่ทันสมัยไปเป็นเวอร์ชันดั้งเดิมที่เข้ากันได้กับเบราว์เซอร์รุ่นเก่า ตัวอย่างเช่น กำหนดฟังก์ชันลูกศร ES2015:

 [2, 4, 6].map((n) => n * 2);

…Babel จะแปลงเป็นเวอร์ชัน ES5:

 [2, 4, 6].map(function(n) { return n * 2; });

Transpiling PHP คืออะไร?

สิ่งที่อาจเกิดขึ้นใหม่ในการพัฒนาเว็บคือความเป็นไปได้ของการแปลงโค้ดฝั่งเซิร์ฟเวอร์ โดยเฉพาะ PHP

Transpiling PHP ทำงานในลักษณะเดียวกับ transpiling JavaScript: ซอร์สโค้ดจากเวอร์ชัน PHP ที่ทันสมัยจะถูกแปลงเป็นโค้ดที่เทียบเท่ากับเวอร์ชัน PHP ที่เก่ากว่า

ตามตัวอย่างเดิม ฟังก์ชันลูกศรจาก PHP 7.4:

 $nums = array_map(fn($n) => $n * 2, [2, 4, 6]);

…สามารถแปลงเป็นเวอร์ชัน PHP 7.3 ที่เทียบเท่าได้:

 $nums = array_map( function ($n) { return $n * 2; }, [2, 4, 6] );

ฟังก์ชั่นลูกศรสามารถ transpiled ได้เนื่องจากเป็นวากยสัมพันธ์ของน้ำตาล นั่นคือไวยากรณ์ใหม่เพื่อสร้างพฤติกรรมที่มีอยู่ นี่คือผลไม้ห้อยต่ำ

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

 function someFunction(float|int $param): string|float|int|null { // ... }

ในสถานการณ์เหล่านี้ การ transpiling สามารถทำได้ตราบใดที่คุณสมบัติใหม่จำเป็นสำหรับการพัฒนา แต่ไม่ใช่สำหรับการผลิต จากนั้น เราก็สามารถลบคุณลักษณะทั้งหมดออกจากโค้ดทรานสพิลได้โดยไม่มีผลกระทบร้ายแรง

ตัวอย่างหนึ่งคือประเภทสหภาพแรงงาน คุณลักษณะนี้ใช้เพื่อตรวจสอบว่าไม่มีการจับคู่ระหว่างประเภทอินพุตกับค่าที่ให้มา ซึ่งช่วยป้องกันจุดบกพร่อง หากมีข้อขัดแย้งกับประเภท จะมีข้อผิดพลาดในการพัฒนาอยู่แล้ว และเราควรตรวจสอบและแก้ไขก่อนที่โค้ดจะเข้าสู่การใช้งานจริง

ดังนั้น เราสามารถลบคุณลักษณะนี้ออกจากโค้ดสำหรับใช้งานจริงได้:

 function someFunction($param) { // ... }

หากข้อผิดพลาดยังคงเกิดขึ้นในการผลิต ข้อความแสดงข้อผิดพลาดที่ส่งออกไปจะแม่นยำน้อยกว่าถ้าเรามีประเภทสหภาพแรงงาน อย่างไรก็ตาม ข้อเสียที่อาจเกิดขึ้นนี้เกินดุลโดยสามารถใช้ประเภทสหภาพได้ตั้งแต่แรก

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

ข้อดีของการ Transpiling PHP Code

Transpiling ช่วยให้สามารถเขียนโค้ดแอปพลิเคชันโดยใช้ PHP เวอร์ชันล่าสุดและสร้างเวอร์ชันที่ใช้งานได้ในสภาพแวดล้อมที่ใช้ PHP เวอร์ชันเก่ากว่า

ซึ่งจะเป็นประโยชน์อย่างยิ่งสำหรับนักพัฒนาที่สร้างผลิตภัณฑ์สำหรับระบบจัดการเนื้อหาแบบเดิม (CMS) ตัวอย่างเช่น WordPress ยังคงรองรับ PHP 5.6 อย่างเป็นทางการ (แม้ว่าจะแนะนำ PHP 7.4+) เปอร์เซ็นต์ของไซต์ WordPress ที่ใช้ PHP เวอร์ชัน 5.6 ถึง 7.2 ซึ่งเป็นจุดสิ้นสุดของชีวิต (EOL) ทั้งหมด หมายความว่าพวกเขาไม่ได้รับการอัปเดตด้านความปลอดภัยอีกต่อไป อยู่ที่ 34.8% และไซต์ที่ทำงานบนเวอร์ชัน PHP อื่นที่ไม่ใช่ 8.0 อยู่ที่ 99.5% มหันต์:

การใช้งาน WordPress ตามเวอร์ชัน
สถิติการใช้งาน WordPress ตามเวอร์ชัน ที่มาของภาพ: WordPress

ดังนั้น ธีมและปลั๊กอินของ WordPress ที่กำหนดเป้าหมายไปยังผู้ชมทั่วโลกมักจะถูกเข้ารหัสด้วย PHP เวอร์ชันเก่าเพื่อเพิ่มการเข้าถึงที่เป็นไปได้ ขอบคุณ transpiling สิ่งเหล่านี้สามารถเข้ารหัสได้โดยใช้ PHP 8.0 และยังคงเผยแพร่สำหรับเวอร์ชัน PHP ที่เก่ากว่า ดังนั้นจึงกำหนดเป้าหมายผู้ใช้ให้ได้มากที่สุด

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

นี่เป็นกรณีของ Drupal ซึ่งต้องใช้ PHP 7.3 ขอบคุณ transpiling นักพัฒนาสามารถสร้างโมดูล Drupal ที่เผยแพร่ต่อสาธารณะได้โดยใช้ PHP 8.0 และเผยแพร่ด้วย PHP 7.3

อีกตัวอย่างหนึ่งคือเมื่อสร้างโค้ดที่กำหนดเองสำหรับลูกค้าที่ไม่สามารถเรียกใช้ PHP 8.0 ในสภาพแวดล้อมของตนได้เนื่องจากสาเหตุใดสาเหตุหนึ่ง อย่างไรก็ตาม ต้องขอบคุณ transpiling นักพัฒนายังสามารถเขียนโค้ดสิ่งที่ส่งมาด้วยโดยใช้ PHP 8.0 และรันบนสภาพแวดล้อมแบบเดิมเหล่านั้นได้

เมื่อใดควร Transpil PHP

โค้ด PHP สามารถ transpiled ได้เสมอ เว้นแต่จะมีคุณลักษณะ PHP บางอย่างที่ไม่เทียบเท่ากับ PHP เวอร์ชันก่อนหน้า

นั่นอาจเป็นกรณีของแอตทริบิวต์ที่แนะนำใน PHP 8.0:

 #[SomeAttr] function someFunc() {} #[AnotherAttr] class SomeClass {}

ในตัวอย่างก่อนหน้านี้ที่ใช้ฟังก์ชันลูกศร โค้ดสามารถ transpiled ได้เนื่องจากฟังก์ชันลูกศรเป็นน้ำตาลแบบวากยสัมพันธ์ ในทางตรงกันข้าม คุณลักษณะจะสร้างพฤติกรรมใหม่ทั้งหมด ลักษณะการทำงานนี้ยังสามารถทำซ้ำได้ด้วย PHP 7.4 และต่ำกว่า แต่ด้วยการเข้ารหัสด้วยตนเองเท่านั้น นั่นคือไม่ได้อิงตามเครื่องมือหรือกระบวนการโดยอัตโนมัติ (AI สามารถให้โซลูชันได้ แต่เรายังไม่ได้ดำเนินการ)

แอตทริบิวต์ที่มีไว้สำหรับใช้ในการพัฒนา เช่น #[Deprecated] สามารถลบออกได้ในลักษณะเดียวกับการลบประเภทสหภาพแรงงาน แต่แอตทริบิวต์ที่ปรับเปลี่ยนพฤติกรรมของแอปพลิเคชันในการผลิตไม่สามารถลบออกได้ และไม่สามารถถ่ายทอดโดยตรงได้เช่นกัน

ณ วันนี้ ไม่มี transpiler ใดที่สามารถรับโค้ดที่มีแอตทริบิวต์ PHP 8.0 และสร้างโค้ด PHP 7.4 ที่เทียบเท่าได้โดยอัตโนมัติ ดังนั้น หากโค้ด PHP ของคุณจำเป็นต้องใช้แอตทริบิวต์ การทรานสไพล์จะยากหรือไม่สามารถทำได้

ฟีเจอร์ PHP ที่สามารถ Transpiled ได้

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

เวอร์ชัน PHP คุณสมบัติ
7.1 ทุกอย่าง
7.2 – ประเภท object
– การขยายประเภทพารามิเตอร์
PREG_UNMATCHED_AS_NULL ตั้งค่าสถานะใน preg_match
7.3 – การกำหนดอ้างอิงใน list() / การทำลายอาร์เรย์ ( ยกเว้นภายใน foreach — #4376)
– ไวยากรณ์ Heredoc และ Nowdoc ที่ยืดหยุ่น
– เครื่องหมายจุลภาคต่อท้ายในการเรียกใช้ฟังก์ชัน
set(raw)cookie ยอมรับ $option อาร์กิวเมนต์
7.4 – คุณสมบัติที่พิมพ์
– ฟังก์ชั่นลูกศร
– โอเปอเรเตอร์การกำหนดการรวมศูนย์เป็นโมฆะ
– แกะภายในอาร์เรย์
– ตัวคั่นตามตัวอักษร
strip_tags() พร้อมอาร์เรย์ของชื่อแท็ก
– ประเภทผลตอบแทนร่วมและประเภทพารามิเตอร์ที่ขัดแย้งกัน
8.0 – ประเภทสหภาพ
mixed ผสมเทียม
– ประเภทการส่งคืน static
::class บนวัตถุ
match นิพจน์
catch ข้อยกเว้นเฉพาะประเภท
– โอเปอเรเตอร์ที่ปลอดภัยเป็นศูนย์
– การส่งเสริมคุณสมบัติคลาสคอนสตรัคเตอร์
– เครื่องหมายจุลภาคต่อท้ายในรายการพารามิเตอร์และรายการการ use การปิด

PHP Transpilers

ปัจจุบัน มีเครื่องมือหนึ่งสำหรับ transpiling โค้ด PHP: Rector

Rector เป็นเครื่องมือสร้าง PHP ใหม่ ซึ่งแปลงโค้ด PHP ตามกฎที่ตั้งโปรแกรมได้ เราป้อนซอร์สโค้ดและชุดของกฎที่จะเรียกใช้ และอธิการบดีจะแปลงรหัส

อธิการบดีดำเนินการผ่านบรรทัดคำสั่ง ติดตั้งในโปรเจ็กต์ผ่าน Composer เมื่อดำเนินการ Rector จะแสดงผล "diff" (ส่วนเพิ่มเติมเป็นสีเขียว ลบออกด้วยสีแดง) ของโค้ดก่อนและหลังการแปลง:

เอาต์พุต "diff" จากอธิการ
“diff” เอาต์พุตจากอธิการ

PHP เวอร์ชันใดที่จะแปลงเป็น

หากต้องการแปลงรหัสข้ามเวอร์ชัน PHP จะต้องสร้างกฎที่เกี่ยวข้อง

ปัจจุบัน ไลบรารี Rector มีกฎส่วนใหญ่สำหรับการทรานสปิลโค้ดภายในช่วง PHP 8.0 ถึง 7.1 ดังนั้น เราจึงสามารถแปลงรหัส PHP ของเราได้ไกลถึงเวอร์ชัน 7.1 ได้อย่างน่าเชื่อถือ

นอกจากนี้ยังมีกฎสำหรับการทรานสปิลจาก PHP 7.1 เป็น 7.0 และจาก 7.0 เป็น 5.6 แต่สิ่งเหล่านี้ไม่ได้ครอบคลุมทั้งหมด งานกำลังดำเนินการเพื่อให้เสร็จสมบูรณ์ ดังนั้นในที่สุดเราอาจแปลงโค้ด PHP ลงไปเป็นเวอร์ชัน 5.6

ขนย้าย vs Backporting

Backporting คล้ายกับ transpiling แต่ง่ายกว่า รหัส Backporting ไม่จำเป็นต้องอาศัยคุณสมบัติใหม่จากภาษา แต่สามารถใช้ฟังก์ชันเดียวกันนี้กับเวอร์ชันเก่าของภาษาได้โดยการคัดลอก/วาง/ปรับโค้ดที่เกี่ยวข้องจากเวอร์ชันใหม่ของภาษา

ตัวอย่างเช่น ฟังก์ชัน str_contains ถูกนำมาใช้ใน PHP 8.0 ฟังก์ชันเดียวกันสำหรับ PHP 7.4 และต่ำกว่าสามารถใช้งานได้ง่ายดังนี้:

 if (!defined('PHP_VERSION_ID') || (defined('PHP_VERSION_ID') && PHP_VERSION_ID < 80000)) { if (!function_exists('str_contains')) { /** * Checks if a string contains another * * @param string $haystack The string to search in * @param string $needle The string to search * @return boolean Returns TRUE if the needle was found in haystack, FALSE otherwise. */ function str_contains(string $haystack, string $needle): bool { return strpos($haystack, $needle) !== false; } } }

เนื่องจาก backporting ง่ายกว่า transpiling เราควรเลือกใช้โซลูชันนี้ทุกครั้งที่ backporting ทำงาน

เกี่ยวกับช่วงระหว่าง PHP 8.0 ถึง 7.1 เราสามารถใช้ไลบรารี polyfill ของ Symfony:

  • Polyfill PHP 7.1
  • Polyfill PHP 7.2
  • Polyfill PHP 7.3
  • Polyfill PHP 7.4
  • Polyfill PHP 8.0

ไลบรารีเหล่านี้ backport ฟังก์ชัน คลาส ค่าคงที่ และอินเทอร์เฟซต่อไปนี้:

เวอร์ชัน PHP คุณสมบัติ
7.2 ฟังก์ชั่น:
  • spl_object_id
  • utf8_encode
  • utf8_decode

ค่าคงที่:

  • PHP_FLOAT_*
  • PHP_OS_FAMILY
7.3 ฟังก์ชั่น:
  • array_key_first
  • array_key_last
  • hrtime
  • is_countable

ข้อยกเว้น:

  • JsonException
7.4 ฟังก์ชั่น:
  • get_mangled_object_vars
  • mb_str_split
  • password_algos
8.0 อินเทอร์เฟซ:
  • Stringable

ชั้นเรียน:

  • ValueError
  • UnhandledMatchError

ค่าคงที่:

  • FILTER_VALIDATE_BOOL

ฟังก์ชั่น:

  • fdiv
  • get_debug_type
  • preg_last_error_msg
  • str_contains
  • str_starts_with
  • str_ends_with
  • get_resource_id

ตัวอย่างของ Transpiled PHP

มาดูตัวอย่างโค้ด PHP ที่ทรานสพิล และบางแพ็กเกจที่ทรานสพิลแบบเต็มกัน

รหัส PHP

นิพจน์การ match ถูกนำมาใช้ใน PHP 8.0 รหัสที่มานี้:

 function getFieldValue(string $fieldName): ?string { return match($fieldName) { 'foo' => 'foofoo', 'bar' => 'barbar', 'baz' => 'bazbaz', default => null, }; }

…จะถูกแปลงเป็นเวอร์ชัน PHP 7.4 ที่เทียบเท่า โดยใช้ตัวดำเนินการ switch :

 function getFieldValue(string $fieldName): ?string { switch ($fieldName) { case 'foo': return 'foofoo'; case 'bar': return 'barbar'; case 'baz': return 'bazbaz'; default: return null; } }

ตัวดำเนินการ nullsafe ยังถูกนำมาใช้ใน PHP 8.0:

 public function getValue(TypeResolverInterface $typeResolver): ?string { return $this->getResolver($typeResolver)?->getValue(); }

รหัส transpiled จำเป็นต้องกำหนดค่าของการดำเนินการให้กับตัวแปรใหม่ก่อน เพื่อหลีกเลี่ยงการดำเนินการสองครั้ง:

 public function getValue(TypeResolverInterface $typeResolver): ?string { return ($val = $this->getResolver($typeResolver)) ? $val->getValue() : null; }

คุณลักษณะการส่งเสริมคุณสมบัติคอนสตรัคเตอร์ซึ่งเปิดตัวใน PHP 8.0 ช่วยให้นักพัฒนาเขียนโค้ดน้อยลง:

 class QueryResolver { function __construct(protected QueryFormatter $queryFormatter) { } }

เมื่อทำการ transpiling สำหรับ PHP 7.4 จะมีการสร้างโค้ดทั้งหมด:

 class QueryResolver { protected QueryFormatter $queryFormatter; function __construct(QueryFormatter $queryFormatter) { $this->queryFormatter = $queryFormatter; } }

โค้ด transpiled ด้านบนมีคุณสมบัติการพิมพ์ ซึ่งถูกนำมาใช้ใน PHP 7.4 การแปลงรหัสนั้นลงไปที่ PHP 7.3 จะแทนที่ด้วย docblocks:

 class QueryResolver { /** * @var QueryFormatter */ protected $queryFormatter; function __construct(QueryFormatter $queryFormatter) { $this->queryFormatter = $queryFormatter; } }

แพ็คเกจ PHP

ไลบรารีต่อไปนี้กำลังถูก transpiled สำหรับการผลิต:

ห้องสมุด/คำอธิบาย รหัส/หมายเหตุ
อธิการบดี
เครื่องมือสร้าง PHP ใหม่ที่ทำให้ทรานสปิลเป็นไปได้
- รหัสแหล่งที่มา
– รหัสถอดรหัส
– หมายเหตุ
มาตรฐานการเข้ารหัสที่ง่าย
เครื่องมือเพื่อให้โค้ด PHP เป็นไปตามชุดของกฎ
- รหัสแหล่งที่มา
– รหัสถอดรหัส
– หมายเหตุ
GraphQL API สำหรับ WordPress
ปลั๊กอินที่ให้บริการเซิร์ฟเวอร์ GraphQL สำหรับ WordPress
- รหัสแหล่งที่มา
– รหัสถอดรหัส
– หมายเหตุ

ข้อดีและข้อเสียของการ Transpiling PHP

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

สิ่งนี้ทำให้เราสามารถเป็นนักพัฒนาที่ดีขึ้นได้อย่างมีประสิทธิภาพ โดยผลิตโค้ดที่มีคุณภาพสูงขึ้น ทั้งนี้เนื่องจากซอร์สโค้ดของเราสามารถใช้ประเภทยูเนี่ยนของ PHP 8.0, คุณสมบัติการพิมพ์ของ PHP 7.4 และประเภทและประเภทเทียมที่แตกต่างกันที่เพิ่มในแต่ละเวอร์ชันใหม่ของ PHP ( mixed จาก PHP 8.0, object จาก PHP 7.2) คุณสมบัติที่ทันสมัยอื่น ๆ ของ PHP

เมื่อใช้คุณสมบัติเหล่านี้ เราสามารถตรวจจับจุดบกพร่องระหว่างการพัฒนาและเขียนโค้ดที่อ่านได้ง่ายขึ้น

ทีนี้มาดูข้อเสียกัน

ต้องมีการเข้ารหัสและบำรุงรักษา

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

ห้องสมุดบุคคลที่สามจะต้องถูกถ่ายโอนด้วย

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

อธิการบดีไม่แจ้งให้เราทราบเมื่อไม่สามารถถ่ายทอดรหัสได้

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

ข้อมูลการดีบักใช้ Transpiled Code ไม่ใช่ซอร์สโค้ด

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

รหัส Transpiled จะต้องนำหน้าด้วย

โปรเจ็กต์ transpiled ของเราและไลบรารีอื่น ๆ ที่ติดตั้งในสภาพแวดล้อมการใช้งานจริงยังสามารถใช้การพึ่งพาบุคคลที่สามเดียวกันได้ การพึ่งพาบุคคลที่สามนี้จะถูก transpiled สำหรับโครงการของเราและเก็บซอร์สโค้ดดั้งเดิมไว้สำหรับไลบรารีอื่น ดังนั้น เวอร์ชัน transpiled จะต้องขึ้นต้นด้วย PHP-Scoper, Strauss หรือเครื่องมืออื่นๆ เพื่อหลีกเลี่ยงความขัดแย้งที่อาจเกิดขึ้น

การขนถ่ายต้องเกิดขึ้นระหว่างการรวมอย่างต่อเนื่อง (CI)

เนื่องจากโค้ดที่ทรานสไพล์จะแทนที่ซอร์สโค้ดโดยธรรมชาติ เราจึงไม่ควรรันกระบวนการทรานสไพล์บนคอมพิวเตอร์ที่กำลังพัฒนาของเรา ไม่เช่นนั้นเราจะเสี่ยงที่จะสร้างผลข้างเคียง การรันกระบวนการในระหว่างการรัน CI นั้นเหมาะสมกว่า (เพิ่มเติมเกี่ยวกับสิ่งนี้ด้านล่าง)

วิธีการ Transpil PHP

อันดับแรก เราต้องติดตั้ง Rector ในโครงการเพื่อการพัฒนาของเรา:

 composer require rector/rector --dev

จากนั้นเราสร้างไฟล์การกำหนดค่า rector.php ในไดเร็กทอรีรากของโปรเจ็กต์ที่มีชุดกฎเกณฑ์ที่จำเป็น ในการดาวน์เกรดโค้ดจาก PHP 8.0 เป็น 7.1 เราใช้การกำหนดค่านี้:

 use Rector\Set\ValueObject\DowngradeSetList; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return static function (ContainerConfigurator $containerConfigurator): void { $containerConfigurator->import(DowngradeSetList::PHP_80); $containerConfigurator->import(DowngradeSetList::PHP_74); $containerConfigurator->import(DowngradeSetList::PHP_73); $containerConfigurator->import(DowngradeSetList::PHP_72); };

เพื่อให้แน่ใจว่ากระบวนการทำงานตามที่คาดไว้ เราสามารถเรียกใช้คำสั่ง process ของ Rector ในโหมดแห้ง โดยส่งตำแหน่งที่จะประมวลผล (ในกรณีนี้ ไฟล์ทั้งหมดภายใต้โฟลเดอร์ src/ ):

 vendor/bin/rector process src --dry-run

ในการดำเนินการ transpiling เราเรียกใช้คำสั่ง process ของ Rector ซึ่งจะแก้ไขไฟล์ภายในตำแหน่งที่มีอยู่:

 vendor/bin/rector process src

โปรดสังเกต: ถ้าเราเรียกใช้ rector process ในคอมพิวเตอร์การพัฒนาของเรา ซอร์สโค้ดจะถูกแปลงในตำแหน่งภายใต้ src/ อย่างไรก็ตาม เราต้องการสร้างโค้ดที่แปลงแล้วในตำแหน่งอื่น เพื่อไม่ให้แทนที่ซอร์สโค้ดเมื่อดาวน์เกรดโค้ด ด้วยเหตุนี้ การรันกระบวนการจึงเหมาะสมที่สุดในระหว่างการรวมแบบต่อเนื่อง

การเพิ่มประสิทธิภาพกระบวนการขนถ่าย

ในการสร้างการส่งมอบ transpiled สำหรับการผลิต ต้องแปลงเฉพาะรหัสสำหรับการผลิตเท่านั้น รหัสที่จำเป็นสำหรับการพัฒนาเท่านั้นสามารถข้ามได้ นั่นหมายความว่าเราสามารถหลีกเลี่ยงการ transpiling การทดสอบทั้งหมด (สำหรับทั้งโครงการของเราและการขึ้นต่อกัน) และการพึ่งพาทั้งหมดเพื่อการพัฒนา

เกี่ยวกับการทดสอบ เราจะรู้แล้วว่าอันไหนของโปรเจ็กต์ของเรา — ตัวอย่างเช่น ภายใต้โฟลเดอร์ tests/ . เราต้องค้นหาด้วยว่าการขึ้นต่อกันอยู่ที่ไหน - ตัวอย่างเช่น ภายใต้โฟลเดอร์ย่อยของไฟล์ tests/ , test/ และ Test/ (สำหรับไลบรารีต่างๆ) จากนั้น เราบอกให้อธิการข้ามการประมวลผลโฟลเดอร์เหล่านี้:

 return static function (ContainerConfigurator $containerConfigurator): void { // ... $parameters->set(Option::SKIP, [ // Skip tests '*/tests/*', '*/test/*', '*/Test/*', ]); };

เกี่ยวกับการพึ่งพา Composer รู้ว่าอันไหนสำหรับการพัฒนา (อันที่อยู่ภายใต้รายการ require-dev ใน composer.json ) และอันไหนสำหรับการผลิต (อันที่อยู่ภายใต้รายการ require )

ในการดึงข้อมูลจาก Composer เส้นทางของการพึ่งพาทั้งหมดสำหรับการผลิต เราเรียกใช้:

 composer info --path --no-dev

คำสั่งนี้จะสร้างรายการการพึ่งพาที่มีชื่อและเส้นทางดังนี้:

 brain/cortex /Users/leo/GitHub/leoloso/PoP/vendor/brain/cortex composer/installers /Users/leo/GitHub/leoloso/PoP/vendor/composer/installers composer/semver /Users/leo/GitHub/leoloso/PoP/vendor/composer/semver guzzlehttp/guzzle /Users/leo/GitHub/leoloso/PoP/vendor/guzzlehttp/guzzle league/pipeline /Users/leo/GitHub/leoloso/PoP/vendor/league/pipeline

เราสามารถแยกพาธทั้งหมดและป้อนเข้าไปในคำสั่ง Rector ซึ่งจะประมวลผลโฟลเดอร์ src/ ของโปรเจ็กต์ของเรา บวกกับโฟลเดอร์เหล่านั้นที่มีการขึ้นต่อกันทั้งหมดสำหรับการผลิต:

 $ paths="$(composer info --path --no-dev | cut -d' ' -f2- | sed 's/ //g' | tr '\n' ' ')" $ vendor/bin/rector process src $paths

การปรับปรุงเพิ่มเติมสามารถป้องกันไม่ให้ Rector ประมวลผลการพึ่งพาเหล่านั้นโดยใช้เวอร์ชัน PHP เป้าหมายอยู่แล้ว หากไลบรารีได้รับการเข้ารหัสด้วย PHP 7.1 (หรือเวอร์ชันใดๆ ด้านล่าง) ก็ไม่จำเป็นต้องแปลงเป็น PHP 7.1

เพื่อให้บรรลุสิ่งนี้ เราสามารถรับรายการไลบรารีที่ต้องใช้ PHP 7.2 ขึ้นไปและประมวลผลเฉพาะไลบรารีเหล่านั้น เราจะได้รับชื่อของไลบรารีเหล่านี้ทั้งหมดผ่านคำสั่ง why-not ของ Composer ดังนี้:

 composer why-not php "7.1.*" | grep -o "\S*\/\S*"

เนื่องจากคำสั่งนี้ใช้ไม่ได้กับแฟ --no-dev เพื่อรวมเฉพาะการพึ่งพาสำหรับการผลิต อันดับแรกเราต้องลบการพึ่งพาสำหรับการพัฒนาและสร้างตัวโหลดอัตโนมัติใหม่ รันคำสั่ง แล้วเพิ่มอีกครั้ง:

 $ composer install --no-dev $ packages=$(composer why-not php "7.1.*" | grep -o "\S*\/\S*") $ composer install

คำสั่ง info --path ของผู้แต่งดึงเส้นทางสำหรับแพ็คเกจด้วยรูปแบบนี้:

 # Executing this command $ composer info psr/cache --path # Produces this response: psr/cache /Users/leo/GitHub/leoloso/PoP/vendor/psr/cache

เราดำเนินการคำสั่งนี้สำหรับรายการทั้งหมดในรายการของเราเพื่อรับเส้นทางทั้งหมดที่จะ transpile:

 for package in $packages do path=$(composer info $package --path | cut -d' ' -f2-) paths="$paths $path" done

สุดท้าย เราจัดเตรียมรายการนี้ให้กับอธิการบดี (รวมถึงโฟลเดอร์ src/ ของโครงการ):

ต้องการโซลูชันโฮสติ้งที่ให้ความได้เปรียบในการแข่งขันหรือไม่? Kinsta มีความเร็วที่น่าทึ่ง การรักษาความปลอดภัยที่ล้ำสมัย และการปรับขนาดอัตโนมัติ ตรวจสอบแผนของเรา

 vendor/bin/rector process src $paths

ข้อผิดพลาดที่ควรหลีกเลี่ยงเมื่อแปลงรหัส

การถอดรหัสโค้ดถือได้ว่าเป็นงานศิลปะ ซึ่งมักต้องมีการปรับแต่งเฉพาะสำหรับโปรเจ็กต์ มาดูปัญหาที่เราอาจจะเจอกันบ้าง

กฎที่ถูกล่ามโซ่ไม่ได้ถูกประมวลผลเสมอไป

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

ตัวอย่างเช่น ไลบรารี symfony/cache มีรหัสนี้:

 final class CacheItem implements ItemInterface { public function tag($tags): ItemInterface { // ... return $this; } }

เมื่อแปลงจาก PHP 7.4 เป็น 7.3 tag ฟังก์ชันต้องได้รับการดัดแปลงสองแบบ:

  • ต้องแปลงประเภทการส่งคืน ItemInterface เป็น self ก่อน เนื่องจากกฎ DowngradeCovariantReturnTypeRector
  • ต้องลบประเภทการส่งคืน self เนื่องจากกฎ DowngradeSelfTypeDeclarationRector

ผลลัพธ์ที่ได้ควรเป็นดังนี้:

 final class CacheItem implements ItemInterface { public function tag($tags) { // ... return $this; } }

อย่างไรก็ตาม อธิการจะแสดงผลเฉพาะขั้นกลางเท่านั้น:

 final class CacheItem implements ItemInterface { public function tag($tags): self { // ... return $this; } }

ปัญหาคืออธิการบดีไม่สามารถควบคุมลำดับการใช้กฎได้ตลอดเวลา

วิธีแก้ไขคือการระบุว่ากฎลูกโซ่ใดที่ยังไม่ได้รับการประมวลผล และเรียกใช้ Rector ใหม่เพื่อนำไปใช้

เพื่อระบุกฎลูกโซ่ เราเรียกใช้ Rector สองครั้งบนซอร์สโค้ดดังนี้:

 $ vendor/bin/rector process src $ vendor/bin/rector process src --dry-run

ครั้งแรก เราเรียกใช้ Rector ตามที่คาดไว้ เพื่อดำเนินการ transpiling ครั้งที่สอง เราใช้ --dry-run เพื่อค้นหาว่ายังมีการเปลี่ยนแปลงที่ต้องทำหรือไม่ หากมี คำสั่งจะออกพร้อมกับรหัสข้อผิดพลาด และเอาต์พุต "diff" จะระบุว่ากฎใดที่ยังสามารถนำไปใช้ได้ นั่นหมายความว่าการวิ่งครั้งแรกยังไม่สมบูรณ์ โดยกฎที่ผูกมัดบางอย่างจะไม่ได้รับการประมวลผล

วิ่งอธิการด้วย --dry-run flag
วิ่งอธิการด้วย –dry-run flag

เมื่อเราระบุกฎลูกโซ่ (หรือกฎ) ที่ไม่ได้ใช้แล้ว เราก็สามารถสร้างไฟล์กำหนดค่า Rector อื่นได้ ตัวอย่างเช่น rector-chained-rule.php จะดำเนินการตามกฎที่ขาดหายไป แทนที่จะประมวลผลกฎครบชุดสำหรับไฟล์ทั้งหมดภายใต้ src/ คราวนี้ เราสามารถเรียกใช้กฎที่ขาดหายไปในไฟล์เฉพาะที่ต้องการนำไปใช้ได้:

 // rector-chained-rule.php use Rector\Core\Configuration\Option; use Rector\DowngradePhp74\Rector\ClassMethod\DowngradeSelfTypeDeclarationRector; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return static function (ContainerConfigurator $containerConfigurator): void { $services = $containerConfigurator->services(); $services->set(DowngradeSelfTypeDeclarationRector::class); $parameters = $containerConfigurator->parameters(); $parameters->set(Option::PATHS, [ __DIR__ . '/vendor/symfony/cache/CacheItem.php', ]); };

สุดท้าย เราบอกอธิการในการผ่านครั้งที่สองเพื่อใช้ไฟล์ปรับแต่งใหม่ผ่านอินพุต --config :

 # First pass with all modifications $ vendor/bin/rector process src # Second pass to fix a specific problem $ vendor/bin/rector process --config=rector-chained-rule.php

การพึ่งพานักแต่งเพลงอาจไม่สอดคล้องกัน

ไลบรารีสามารถประกาศการพึ่งพาที่ถูกกำหนดไว้สำหรับการพัฒนา (เช่น ภายใต้ require-dev ใน composer.json ) แต่ยังคงอ้างอิงโค้ดบางส่วนจากไลบรารีเหล่านี้เพื่อการใช้งานจริง (เช่น ไฟล์บางไฟล์ภายใต้ src/ ไม่ใช่ tests/ )

โดยปกติ นี่ไม่ใช่ปัญหาเพราะโค้ดนั้นอาจไม่สามารถโหลดได้ในการผลิต ดังนั้นจึงไม่มีข้อผิดพลาดในแอปพลิเคชัน อย่างไรก็ตาม เมื่อ Rector ประมวลผลซอร์สโค้ดและการขึ้นต่อกันของซอร์สโค้ด จะตรวจสอบว่าโค้ดที่อ้างอิงทั้งหมดสามารถโหลดได้ อธิการจะโยนข้อผิดพลาดหากไฟล์ใด ๆ อ้างอิงโค้ดบางส่วนจากไลบรารีที่ไม่ได้ติดตั้ง (เพราะถูกประกาศว่าจำเป็นสำหรับการพัฒนาเท่านั้น)

ตัวอย่างเช่น คลาส EarlyExpirationHandler จากคอมโพเนนต์ Cache ของ Symfony ใช้อินเทอร์เฟซ MessageHandlerInterface จากคอมโพเนนต์ Messenger:

 class EarlyExpirationHandler implements MessageHandlerInterface { //... }

อย่างไรก็ตาม symfony/cache ประกาศว่า symfony/messenger เป็นการพึ่งพาสำหรับการพัฒนา จากนั้นเมื่อรัน Rector ในโครงการที่ขึ้นอยู่กับ symfony/cache มันจะเกิดข้อผิดพลาด:

 [ERROR] Could not process "vendor/symfony/cache/Messenger/EarlyExpirationHandler.php" file, due to: "Analyze error: "Class Symfony\Component\Messenger\Handler\MessageHandlerInterface not found.". Include your files in "$parameters->set(Option::AUTOLOAD_PATHS, [...]);" in "rector.php" config. See https://github.com/rectorphp/rector#configuration".

มีสามวิธีแก้ไขปัญหานี้:

  1. ในการกำหนดค่า Rector ให้ข้ามการประมวลผลไฟล์ที่อ้างอิงโค้ดนั้น:
 return static function (ContainerConfigurator $containerConfigurator): void { // ... $parameters->set(Option::SKIP, [ __DIR__ . '/vendor/symfony/cache/Messenger/EarlyExpirationHandler.php', ]); };
  1. ดาวน์โหลดไลบรารีที่หายไปและเพิ่มเส้นทางที่จะโหลดอัตโนมัติโดยอธิการบดี:
 return static function (ContainerConfigurator $containerConfigurator): void { // ... $parameters->set(Option::AUTOLOAD_PATHS, [ __DIR__ . '/vendor/symfony/messenger', ]); };
  1. ให้โปรเจ็กต์ของคุณขึ้นอยู่กับไลบรารีที่ขาดหายไปสำหรับการผลิต:
 composer require symfony/messenger

Transpiling และบูรณาการอย่างต่อเนื่อง

ดังที่ได้กล่าวไว้ก่อนหน้านี้ ในคอมพิวเตอร์การพัฒนาของเรา เราต้องใช้ --dry-run เมื่อรัน Rector มิฉะนั้น ซอร์สโค้ดจะถูกแทนที่ด้วยโค้ด transpiled ด้วยเหตุผลนี้ จึงเหมาะกว่าที่จะเรียกใช้กระบวนการ transpiling จริงในระหว่างการรวมระบบแบบต่อเนื่อง (CI) ซึ่งเราสามารถหมุนนักวิ่งชั่วคราวเพื่อดำเนินการตามกระบวนการ

เวลาที่เหมาะสมในการดำเนินการตามกระบวนการ transpiling คือเมื่อสร้างการเปิดตัวสำหรับโครงการของเรา ตัวอย่างเช่น โค้ดด้านล่างเป็นเวิร์กโฟลว์สำหรับ GitHub Actions ซึ่งสร้างการเปิดตัวของปลั๊กอิน WordPress:

 name: Generate Installable Plugin and Upload as Release Asset on: release: types: [published] jobs: build: name: Build, Downgrade and Upload Release runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/[email protected] - name: Downgrade code for production (to PHP 7.1) run: | composer install vendor/bin/rector process sed -i 's/Requires PHP: 7.4/Requires PHP: 7.1/' graphql-api.php - name: Build project for production run: | composer install --no-dev --optimize-autoloader mkdir build - name: Create artifact uses: montudor/[email protected] with: args: zip -X -r build/graphql-api.zip . -x *.git* node_modules/\* .* "*/\.*" CODE_OF_CONDUCT.md CONTRIBUTING.md ISSUE_TEMPLATE.md PULL_REQUEST_TEMPLATE.md rector.php *.dist composer.* dev-helpers** build** - name: Upload artifact uses: actions/[email protected] with: name: graphql-api path: build/graphql-api.zip - name: Upload to release uses: JasonEtco/[email protected] with: args: build/graphql-api.zip application/zip env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

เวิร์กโฟลว์นี้มีขั้นตอนมาตรฐานในการเปิดตัวปลั๊กอิน WordPress ผ่าน GitHub Actions การเพิ่มใหม่นี้เพื่อแปลงรหัสของปลั๊กอินจาก PHP 7.4 เป็น 7.1 เกิดขึ้นในขั้นตอนนี้:

 - name: Downgrade code for production (to PHP 7.1) run: | vendor/bin/rector process sed -i 's/Requires PHP: 7.4/Requires PHP: 7.1/' graphql-api.php

เมื่อนำมารวมกัน เวิร์กโฟลว์นี้จะดำเนินการตามขั้นตอนต่อไปนี้:

  1. ตรวจสอบซอร์สโค้ดสำหรับปลั๊กอิน WordPress จากที่เก็บ ซึ่งเขียนด้วย PHP 7.4
  2. ติดตั้งการพึ่งพา Composer
  3. แปลงรหัสจาก PHP 7.4 เป็น 7.1
  4. แก้ไขรายการ "ต้องการ PHP" ในส่วนหัวของไฟล์หลักของปลั๊กอินจาก "7.4" เป็น "7.1"
  5. ลบการพึ่งพาที่จำเป็นสำหรับการพัฒนา
  6. สร้างไฟล์ .zip ของปลั๊กอิน ยกเว้นไฟล์ที่ไม่จำเป็นทั้งหมด
  7. อัปโหลดไฟล์ .zip เป็นเนื้อหาเผยแพร่ (และนอกจากนี้ยังเป็นอาร์ติแฟกต์ของ GitHub Action)

การทดสอบ Transpiled Code

เมื่อโค้ดถูกแปลงเป็น PHP 7.1 แล้ว เราจะรู้ได้อย่างไรว่าโค้ดนั้นทำงานได้ดี หรืออีกนัยหนึ่ง เราจะรู้ได้อย่างไรว่ามันถูกแปลงอย่างละเอียดแล้ว และไม่มีโค้ด PHP เวอร์ชันที่สูงกว่าหลงเหลืออยู่เลย?

เราสามารถปรับใช้โซลูชันภายในกระบวนการ CI ได้ เช่นเดียวกับการถอดรหัสโค้ด แนวคิดคือการตั้งค่าสภาพแวดล้อมของนักวิ่งด้วย PHP 7.1 และเรียกใช้ linter บนโค้ด transpiled หากโค้ดใดๆ เข้ากันไม่ได้กับ PHP 7.1 (เช่น คุณสมบัติที่พิมพ์จาก PHP 7.4 ที่ไม่ได้แปลง) ไฟล์ linter จะเกิดข้อผิดพลาด

linter สำหรับ PHP ที่ทำงานได้ดีคือ PHP Parallel Lint เราสามารถติดตั้งไลบรารีนี้เป็นการพึ่งพาสำหรับการพัฒนาในโปรเจ็กต์ของเรา หรือให้กระบวนการ CI ติดตั้งเป็นโปรเจ็กต์ Composer แบบสแตนด์อโลน:

 composer create-project php-parallel-lint/php-parallel-lint

เมื่อใดก็ตามที่โค้ดมี PHP 7.2 ขึ้นไป PHP Parallel Lint จะแสดงข้อผิดพลาดเช่นนี้:

 Run php-parallel-lint/parallel-lint layers/ vendor/ --exclude vendor/symfony/polyfill-ctype/bootstrap80.php --exclude vendor/symfony/polyfill-intl-grapheme/bootstrap80.php --exclude vendor/symfony/polyfill-intl-idn/bootstrap80.php --exclude vendor/symfony/polyfill-intl-normalizer/bootstrap80.php --exclude vendor/symfony/polyfill-mbstring/bootstrap80.php PHP 7.1.33 | 10 parallel jobs ............................................................ 60/2870 (2 %) ............................................................ 120/2870 (4 %) ... ............................................................ 660/2870 (22 %) .............X.............................................. 720/2870 (25 %) ............................................................ 780/2870 (27 %) ... ............................................................ 2820/2870 (98 %) .................................................. 2870/2870 (100 %) Checked 2870 files in 15.4 seconds Syntax error found in 1 file ------------------------------------------------------------ Parse error: layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/graphql-api.php:55 53| '0.8.0', 54| \__('GraphQL API for WordPress', 'graphql-api'), > 55| ))) { 56| $plugin->setup(); 57| } Unexpected ')' in layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/graphql-api.php on line 55 Error: Process completed with exit code 1.

มาเพิ่ม linter ลงในเวิร์กโฟลว์ของ CI ของเรากัน ขั้นตอนในการดำเนินการเพื่อแปลงรหัสจาก PHP 8.0 เป็น 7.1 และทดสอบคือ:

  1. ตรวจสอบซอร์สโค้ด
  2. ให้สภาพแวดล้อมรัน PHP 8.0 ดังนั้นอธิการสามารถตีความซอร์สโค้ดได้
  3. แปลงรหัสเป็น PHP 7.1
  4. ติดตั้งเครื่องมือ linter ของ PHP
  5. เปลี่ยนเวอร์ชัน PHP ของสภาพแวดล้อมเป็น 7.1
  6. เรียกใช้ linter บนโค้ด transpiled

เวิร์กโฟลว์ GitHub Action นี้ทำงาน:

 name: Downgrade PHP tests jobs: main: name: Downgrade code to PHP 7.1 via Rector, and execute tests runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/[email protected] - name: Set-up PHP uses: shivammathur/[email protected] with: php-version: 8.0 coverage: none - name: Local packages - Downgrade PHP code via Rector run: | composer install vendor/bin/rector process # Prepare for testing on PHP 7.1 - name: Install PHP Parallel Lint run: composer create-project php-parallel-lint/php-parallel-lint --ansi - name: Switch to PHP 7.1 uses: shivammathur/[email protected] with: php-version: 7.1 coverage: none # Lint the transpiled code - name: Run PHP Parallel Lint on PHP 7.1 run: php-parallel-lint/parallel-lint src/ vendor/ --exclude vendor/symfony/polyfill-ctype/bootstrap80.php --exclude vendor/symfony/polyfill-intl-grapheme/bootstrap80.php --exclude vendor/symfony/polyfill-intl-idn/bootstrap80.php --exclude vendor/symfony/polyfill-intl-normalizer/bootstrap80.php --exclude vendor/symfony/polyfill-mbstring/bootstrap80.php

โปรดสังเกตว่าไฟล์ bootstrap80.php หลายไฟล์จากไลบรารี polyfill ของ Symfony (ซึ่งไม่จำเป็นต้อง transpiled) ต้องถูกแยกออกจาก linter ไฟล์เหล่านี้มี PHP 8.0 ดังนั้น linter จึงแสดงข้อผิดพลาดเมื่อประมวลผล อย่างไรก็ตาม การยกเว้นไฟล์เหล่านี้จะปลอดภัย เนื่องจากไฟล์จะถูกโหลดในการผลิตเมื่อรัน PHP 8.0 ขึ้นไปเท่านั้น:

 if (\PHP_VERSION_ID >= 80000) { return require __DIR__.'/bootstrap80.php'; }

ไม่ว่าคุณจะสร้างปลั๊กอินสาธารณะสำหรับ WordPress หรือกำลังอัปเดตโค้ดดั้งเดิม มีหลายสาเหตุที่อาจใช้ PHP เวอร์ชันล่าสุดไม่ได้ เรียนรู้ว่า transpiling สามารถช่วยในคู่มือนี้ได้อย่างไร คลิกเพื่อทวีต

สรุป

บทความนี้สอนเราถึงวิธีการ transpile โค้ด PHP ของเรา ทำให้เราใช้ PHP 8.0 ในซอร์สโค้ด และสร้างรีลีสที่ทำงานบน PHP 7.1 ได้ Transpiling ทำได้โดยใช้ Rector ซึ่งเป็นเครื่องมือสร้าง PHP ใหม่

การแปลงรหัสของเราทำให้เราเป็นนักพัฒนาที่ดีขึ้น เนื่องจากเราสามารถตรวจจับจุดบกพร่องในการพัฒนาและสร้างโค้ดที่อ่านและเข้าใจได้ง่ายขึ้นอย่างเป็นธรรมชาติ

Transpiling ยังช่วยให้เราสามารถแยกโค้ดของเรากับข้อกำหนด PHP เฉพาะจาก CMS ตอนนี้เราสามารถทำได้หากต้องการใช้ PHP เวอร์ชันล่าสุดเพื่อสร้างปลั๊กอิน WordPress หรือโมดูล Drupal ที่เผยแพร่ต่อสาธารณะโดยไม่จำกัดฐานผู้ใช้ของเราอย่างรุนแรง

คุณมีคำถามใด ๆ เกี่ยวกับการแปลง PHP หรือไม่? แจ้งให้เราทราบในส่วนความคิดเห็น!