Den Ultimate Guide fir PHP Code ze transpiléieren
An idealen Ëmstänn sollte mir PHP 8.0 benotzen (déi lescht Versioun vum Schreiwen) fir all eis Siten an aktualiséieren soubal eng nei Versioun verëffentlecht gëtt. Wéi och ëmmer, Entwéckler mussen dacks mat fréiere PHP Versiounen schaffen, sou wéi wann Dir en ëffentleche Plugin fir WordPress erstellt oder mat Legacy Code schafft, wat d'Upgrade vum Webserver Ëmfeld behënnert.
An dëse Situatioune kënne mir d'Hoffnung opginn fir de leschten PHP Code ze benotzen. Awer et gëtt eng besser Alternativ: mir kënnen nach ëmmer eise Quellcode mat PHP 8.0 schreiwen an en op eng fréier PHP Versioun transpiléieren - souguer op PHP 7.1.
An dësem Guide léiere mir Iech alles wat Dir wësse musst iwwer PHP Code transpiléieren.
Wat ass Transpiléieren?
Transpiling konvertéiert Quellcode vun enger Programméierungssprooch an en gläichwäertege Quellcode vun der selwechter oder enger anerer Programméierungssprooch.
Transpiléieren ass keen neit Konzept an der Webentwécklung: Client-Säit Entwéckler wäerten zimlech wahrscheinlech mat Babel vertraut sinn, en Transpiler fir JavaScript Code.
Babel konvertéiert JavaScript Code vun der moderner ECMAScript 2015+ Versioun an eng legacy Versioun kompatibel mat eelere Browser. Zum Beispill, kritt eng ES2015 Pfeilfunktioun:
[2, 4, 6].map((n) => n * 2);
... Babel wäert et an seng ES5 Versioun ëmsetzen:
[2, 4, 6].map(function(n) {
return n * 2;
});
Wat ass PHP Transpiléieren?
Wat potenziell nei an der Webentwécklung ass, ass d'Méiglechkeet fir Server-Säit Code ze transpiléieren, besonnesch PHP.
Transpiléiere vu PHP funktionnéiert déiselwecht wéi JavaScript transpiléieren: Quellcode vun enger moderner PHP Versioun gëtt an en gläichwäertege Code fir eng méi al PHP Versioun ëmgewandelt.
No deemselwechte Beispill wéi virdrun, eng Pfeilfunktioun vu PHP 7.4:
$nums = array_map(fn($n) => $n * 2, [2, 4, 6]);
...kann a seng gläichwäerteg PHP 7.3 Versioun transpiléiert ginn:
$nums = array_map(
function ($n) {
return $n * 2;
},
[2, 4, 6]
);
Pfeilfunktiounen kënnen transpiléiert ginn well se syntaktesch Zocker sinn, also eng nei Syntax fir en existent Verhalen ze produzéieren. Dëst ass déi niddereg hängend Fruucht.
Wéi och ëmmer, et ginn och nei Features déi en neit Verhalen erstellen, an als solch gëtt et kee gläichwäertege Code fir fréier Versioune vu PHP. Dat ass de Fall mat Gewerkschaftstypen, a PHP 8.0 agefouert:
function someFunction(float|int $param): string|float|int|null
{
// ...
}
An dëse Situatiounen kann d'Transpilatioun nach ëmmer gemaach ginn soulaang déi nei Feature fir d'Entwécklung erfuerderlech ass awer net fir d'Produktioun. Da kënne mir d'Feature ganz einfach aus dem transpiléierte Code läschen ouni sérieux Konsequenzen.
Een esou Beispill ass Gewerkschaftstypen. Dës Fonktioun gëtt benotzt fir ze kontrolléieren ob et kee Mëssverständnis tëscht der Inputtyp a sengem geliwwerte Wäert ass, wat hëlleft Bugs ze vermeiden. Wann et e Konflikt mat Typen ass, gëtt et e Feeler schonn an der Entwécklung, a mir sollten et fänken a fixéieren ier de Code d'Produktioun erreecht.
Dofir kënne mir eis leeschten d'Feature aus dem Code fir d'Produktioun ze läschen:
function someFunction($param)
{
// ...
}
Wann de Feeler geschitt nach an der Produktioun, wäert de geheien Feeler Message manner präziist wéi wa mir Gewerkschaft Zorte haten. Wéi och ëmmer, dëse potenziellen Nodeel gëtt iwwerwältegt andeems Dir Gewerkschaftstypen iwwerhaapt benotze kënnt.
Virdeeler vun Transpiling PHP Code
Transpiling erméiglecht et eng Applikatioun mat der leschter Versioun vu PHP ze codéieren an eng Verëffentlechung ze produzéieren déi och an Ëmfeld funktionnéiert, déi méi al Versioune vu PHP lafen.
Dëst kann besonnesch nëtzlech sinn fir Entwéckler déi Produkter fir Legacy Content Management Systemer (CMS) erstellen. WordPress, zum Beispill, ënnerstëtzt nach ëmmer offiziell PHP 5.6 (och wann et PHP 7.4+ recommandéiert). De Prozentsaz vu WordPress Siten, déi PHP Versiounen 5.6 bis 7.2 lafen - déi all End-of-Life (EOL) sinn, dat heescht datt se keng Sécherheetsupdate méi kréien - steet op e wesentlechen 34.8%, an déi lafen op all PHP Versioun anescht wéi 8.0 steet op ganz 99.5%:
Dofir wäerte WordPress Themen a Plugins, déi op e globale Publikum gezielt sinn, ganz wahrscheinlech mat enger aler Versioun vu PHP kodéiert ginn fir hir méiglech Erreechung ze erhéijen. Dank der Transpiléierung kënnen dës mat PHP 8.0 kodéiert ginn, an nach ëmmer fir eng méi al PHP Versioun verëffentlecht ginn, sou datt esou vill Benotzer wéi méiglech gezielt ginn.
Tatsächlech kann all Applikatioun déi all PHP Versioun aner wéi déi lescht (och am Beräich vun den aktuell ënnerstëtzte PHP Versiounen) ënnerstëtzen, profitéieren.
Dëst ass de Fall mat Drupal, wat PHP 7.3 erfuerdert. Dank der Transpiléierung kënnen d'Entwéckler ëffentlech verfügbar Drupal Moduler mat PHP 8.0 erstellen, a se mat PHP 7.3 befreien.
En anert Beispill ass wann Dir personaliséiert Code erstellt fir Clienten déi PHP 8.0 an hiren Ëmfeld net aus engem oder anere Grond lafen kënnen. Trotzdem, dank der Transpiléierung, kënnen d'Entwéckler nach ëmmer hir Liwwerungen mat PHP 8.0 codéieren an se op dës legacy Ëmfeld lafen.
Wéini PHP ze transpiléieren
PHP Code kann ëmmer transpiléiert ginn, ausser et enthält eng PHP Feature déi keen Äquivalent an der viregter Versioun vu PHP huet.
Dat ass méiglecherweis de Fall mat Attributer, a PHP 8.0 agefouert:
#[SomeAttr]
function someFunc() {}
#[AnotherAttr]
class SomeClass {}
Am fréiere Beispill mat Pfeilfunktiounen kann de Code transpiléiert ginn well Pfeilfunktiounen syntaktesch Zocker sinn. Attributer, am Géigesaz, kreéieren komplett neit Verhalen. Dëst Verhalen kéint och mat PHP 7.4 a méi reproduzéiert ginn, awer nëmmen duerch manuell Kodéierung, also net automatesch baséiert op engem Tool oder Prozess (AI kéint eng Léisung ubidden, awer mir sinn nach net do).
Attributer geduecht fir Entwécklung benotzt, wéi #[Deprecated]
, kann déi selwecht Manéier geläscht ginn, datt Gewerkschaft Zorte geläscht ginn. Awer Attributer déi d'Verhalen vun der Applikatioun an der Produktioun änneren kënnen net geläscht ginn, a si kënnen och net direkt transpiléiert ginn.
Vun haut un kann keen Transpiler Code mat PHP 8.0 Attributer huelen an automatesch säin gläichwäertege PHP 7.4 Code produzéieren. Dofir, wann Äre PHP Code Attributer muss benotzen, dann transpiléiere wäert et schwéier oder onméiglech sinn.
PHP Features déi transpiléiert kënne ginn
Dëst sinn d'Features vu PHP 7.1 a méi héich, déi momentan transpiléiert kënne ginn. Wann Äre Code nëmmen dës Funktiounen benotzt, kënnt Dir d'Sécherheet genéissen datt Är transpiléiert Applikatioun funktionnéiert. Soss musst Dir beurteelen ob den transpiléierten Code Feeler produzéiert.
PHP Versioun | Eegeschaften |
---|---|
7.1 | alles |
7.2 | - object Typ- Erweiderung vum Parametertyp - PREG_UNMATCHED_AS_NULL Fändel an preg_match |
7.3 | - Referenzaufgaben an list() / Array destrukturéieren (Ausser bannen foreach — #4376)- Flexibel Heredoc an Nowdoc Syntax - Verfollegt Kommaen a Funktiounen Uruff - set(raw)cookie akzeptéiert $ Optioun Argument |
7.4 | - Typen Eegeschafte - Pfeil Funktiounen - Null coalescing Aufgab Bedreiwer - Auspacken bannent Arrays - Numeresch literal Separator - strip_tags() mat enger Rei vun Tag Nimm- covariant Retour Typen a contravariant Param Typen |
8.0 | - Unioun Zorte - mixed pseudo Typ- static zréck Typ- ::class magesch konstant op Objete- match Ausdrock- catch Ausnahmen nëmmen no Typ- Null-sécher Bedreiwer - Klass constructor Immobilie Promotioun - Trailing Kommaen a Parameterlëschten a Schließung use Lëschten |
PHP Transpiler
De Moment gëtt et een Tool fir PHP Code ze transpiléieren: Rector.
Rector ass e PHP-Rekonstruktor-Tool, deen PHP-Code konvertéiert baséiert op programméierbare Reegelen. Mir Input de Quellcode an de Set vu Regelen fir ze lafen, an de Rector wäert de Code transforméieren.
De Rector gëtt iwwer Kommandozeil operéiert, am Projet iwwer Composer installéiert. Wann ausgefouert gëtt, wäert de Rector en "diff" ausginn (Ergänzunge a gréng, Ewechhuele rout) vum Code virun an no der Konversioun:
Wéi eng Versioun vu PHP fir ze transpiléieren
Fir Code iwwer PHP Versiounen ze transpiléieren, mussen déi entspriechend Regelen erstallt ginn.
Haut enthält d'Rektorbibliothéik déi meescht Regele fir de Code ze transpiléieren am Beräich vu PHP 8.0 bis 7.1. Dofir kënne mir eis PHP Code zouverlässeg transpiléieren sou wäit wéi d'Versioun 7.1.
Et ginn och Regele fir Transpilatioun vu PHP 7.1 op 7.0 a vu 7.0 op 5.6, awer dës sinn net ustrengend. D'Aarbecht ass amgaang fir se ze kompletéieren, sou datt mir eventuell PHP-Code bis op d'Versioun 5.6 transpiléiere kënnen.
Transpiléieren vs Backporting
Backporting ass ähnlech wéi transpiléieren, awer méi einfach. Backporting Code vertrauen net onbedéngt op nei Features vun enger Sprooch. Amplaz kann déi selwecht Funktionalitéit fir eng méi al Versioun vun der Sprooch geliwwert ginn andeems Dir de entspriechende Code vun der neier Versioun vun der Sprooch kopéiert/paste/adaptéiert.
Zum Beispill, d'Funktioun str_contains
gouf a PHP 8.0 agefouert. Déi selwecht Funktioun fir PHP 7.4 an ënnen kann einfach esou implementéiert ginn:
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;
}
}
}
Well Backporting méi einfach ass wéi transpiléieren, sollte mir fir dës Léisung wielen wann de Backporting d'Aarbecht mécht.
Wat de Beräich tëscht PHP 8.0 bis 7.1 ugeet, kënne mir d'Symfony Polyfill Bibliothéike benotzen:
- Polyfill PHP 7.1
- Polyfill PHP 7.2
- Polyfill PHP 7.3
- Polyfill PHP 7.4
- Polyfill PHP 8.0
Dës Bibliothéiken backportéieren déi folgend Funktiounen, Klassen, Konstanten an Interfaces:
PHP Versioun | Eegeschaften |
---|---|
7.2 | Funktiounen:
Konstanten:
|
7.3 | Funktiounen:
Ausnahmen:
|
7.4 | Funktiounen:
|
8.0 | Schnëttplazen:
Course:
Konstanten:
Funktiounen:
|
Beispiller vun Transpiled PHP
Loosst eis e puer Beispiller vum transpiléierten PHP Code iwwerpréiwen, an e puer Packagen déi komplett transpiléiert ginn.
PHP Code
d' match
Ausdrock gouf a PHP 8.0 agefouert. Dëse Quellcode:
function getFieldValue(string $fieldName): ?string
{
return match($fieldName) {
'foo' => 'foofoo',
'bar' => 'barbar',
'baz' => 'bazbaz',
default => null,
};
}
... wäert op seng gläichwäerteg PHP 7.4 Versioun transpiléiert ginn, mat der switch
Bedreiwer:
function getFieldValue(string $fieldName): ?string
{
switch ($fieldName) {
case 'foo':
return 'foofoo';
case 'bar':
return 'barbar';
case 'baz':
return 'bazbaz';
default:
return null;
}
}
Den nullsafe Bedreiwer gouf och a PHP 8.0 agefouert:
public function getValue(TypeResolverInterface $typeResolver): ?string
{
return $this->getResolver($typeResolver)?->getValue();
}
Den transpiléierten Code muss als éischt de Wäert vun der Operatioun un eng nei Variabel zouzeschreiwen, fir d'Operatioun zweemol auszeféieren:
public function getValue(TypeResolverInterface $typeResolver): ?string
{
return ($val = $this->getResolver($typeResolver)) ? $val->getValue() : null;
}
D'Constructor Property Promotiouns Feature, och a PHP 8.0 agefouert, erlaabt d'Entwéckler manner Code ze schreiwen:
class QueryResolver
{
function __construct(protected QueryFormatter $queryFormatter)
{
}
}
Wann Dir et fir PHP 7.4 transpiléiert, gëtt dat ganzt Stéck Code produzéiert:
class QueryResolver
{
protected QueryFormatter $queryFormatter;
function __construct(QueryFormatter $queryFormatter)
{
$this->queryFormatter = $queryFormatter;
}
}
Den transpiléierten Code uewendriwwer enthält getippten Eegeschaften, déi a PHP 7.4 agefouert goufen. Transpiléiere vun deem Code erof op PHP 7.3 ersetzt se mat docblocks:
class QueryResolver
{
/**
* @var QueryFormatter
*/
protected $queryFormatter;
function __construct(QueryFormatter $queryFormatter)
{
$this->queryFormatter = $queryFormatter;
}
}
PHP Packagen
Déi folgend Bibliothéike gi fir d'Produktioun transpiléiert:
Bibliothéik / Beschreiwung | Code / Notizen |
---|---|
Recteur PHP-Rekonstruktor-Tool dat Transpiléiere méiglech mécht |
- Source Code - Transpiléiert Code - Notizen |
Einfach Kodéierungsnormen Tool fir PHP Code un enger Rei vu Reegelen ze halen |
- Source Code - Transpiléiert Code - Notizen |
GraphQL API fir WordPress Plugin ubitt e GraphQL Server fir WordPress |
- Source Code - Transpiléiert Code - Notizen |
Virdeeler an Nodeeler vum Transpiléiere vu PHP
De Virdeel vum Transpiléiere vu PHP gouf scho beschriwwen: et erlaabt de Quellcode PHP 8.0 ze benotzen (dh déi lescht Versioun vu PHP), déi an eng méi niddereg Versioun fir PHP transforméiert gëtt fir d'Produktioun an enger legacy Applikatioun oder Ëmfeld ze lafen.
Dëst erlaabt eis effektiv besser Entwéckler ze ginn, Code mat méi héijer Qualitéit ze produzéieren. Dëst ass well eise Quellcode kann PHP 8.0 Gewerkschaftstypen benotzen, PHP 7.4 getippten Eegeschaften, an déi verschidden Aarten a Pseudo-Typen déi zu all nei Versioun vu PHP bäigefüügt ginn (mixed
vu PHP 8.0, object
vu PHP 7.2), ënner anerem modernen Features vu PHP.
Mat dëse Fonctiounen kënne mir Bugs während der Entwécklung besser fangen a Code schreiwen deen méi einfach ass ze liesen.
Loosst eis elo d'Nodeeler kucken.
Et muss kodéiert a gehale ginn
De Rector kann de Code automatesch transpiléieren, awer de Prozess wäert méiglecherweis e puer manuelle Input erfuerderen fir et mat eisem spezifesche Setup ze schaffen.
Drëtt Partei Bibliothéike mussen och transpiléiert ginn
Dëst gëtt en Thema wann se transpiléieren Feeler produzéiert well mir dann an hire Quellcode musse verdéiwen fir de méigleche Grond erauszefannen. Wann de Problem ka fixéiert ginn an de Projet ass Open Source, musse mir eng Pull-Ufro ofginn. Wann d'Bibliothéik net Open Source ass, kënne mir e Stroossespär treffen.
De Rektor informéiert eis net wann de Code net kann transpiléiert ginn
Wann de Quellcode PHP 8.0 Attributer enthält oder all aner Feature déi net transpiléiert ka ginn, kënne mir net weidergoen. Wéi och ëmmer, de Rektor wäert dës Konditioun net iwwerpréiwen, also musse mir et manuell maachen. Dëst ass vläicht net e grousse Problem betreffend eisen eegene Quellcode well mir et scho vertraut sinn, awer et kéint en Hindernis betreffend Drëtt Partei Ofhängegkeeten ginn.
Debugging Informatioun benotzt den transpiléierten Code, net de Quellcode
Wann d'Applikatioun e Fehlermeldung mat engem Stackspur an der Produktioun produzéiert, weist d'Linnnummer op den transpiléierte Code. Mir musse vum transpiléierten an den originale Code zréck konvertéieren fir déi entspriechend Linnnummer am Quellcode ze fannen.
Den Transpiléierte Code muss och virgeschriwwe sinn
Eis transpiléiert Projet an eng aner Bibliothéik, déi och am Produktiounsëmfeld installéiert ass, kéinten déiselwecht Drëtt Partei Ofhängegkeet benotzen. Dës Ofhängegkeet vun Drëttubidder gëtt fir eise Projet transpiléiert an hält säin originelle Quellcode fir déi aner Bibliothéik. Dofir muss déi transpiléiert Versioun iwwer PHP-Scoper, Strauss oder en anert Tool virgeschriwwe ginn fir potenziell Konflikter ze vermeiden.
Transpiléierung muss stattfannen wärend der kontinuéierlecher Integratioun (CI)
Well den transpiléierten Code natierlech de Quellcode iwwerschreift, sollte mir den Transpiléierungsprozess net op eisen Entwécklungscomputer ausféieren, oder mir riskéieren Nebenwirkungen ze kreéieren. De Prozess während engem CI Run auszeféieren ass méi gëeegent (méi doriwwer hei ënnen).
Wéi PHP transpiléieren
Als éischt musse mir de Rector an eisem Projet fir Entwécklung installéieren:
composer require rector/rector --dev
Mir kreéieren dann eng rector.php
Konfiguratiounsdatei am Root-Verzeichnis vum Projet mat de erfuerderleche Sets vu Reegelen. Fir de Code vun PHP 8.0 op 7.1 erofzesetzen, benotze mir dës Konfiguratioun:
use RectorSetValueObjectDowngradeSetList;
use SymfonyComponentDependencyInjectionLoaderConfiguratorContainerConfigurator;
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);
};
Fir sécherzestellen datt de Prozess wéi erwaart ausféiert, kënne mir de Rector's lafen process
Kommando am dréchene Modus, laanscht d'Plaz(en) fir ze veraarbecht (an dësem Fall all Dateien ënner dem Dossier src/
):
vendor/bin/rector process src --dry-run
Fir d'Transpilatioun auszeféieren, lafe mir Rector's process
Kommando, wat d'Dateien an hirer existéierender Plaz änneren:
vendor/bin/rector process src
Opgepasst: wa mir lafen rector process
an eiser Entwécklung Computeren, de Quelltext wäert am Plaz ëmgerechent ginn, ënner src/
. Wéi och ëmmer, mir wëllen de konvertéierte Code op enger anerer Plaz produzéieren fir de Quellcode net ze iwwerschreiden wann Dir de Code downgradéiert. Aus dësem Grond ass de Prozess am meeschte gëeegent wärend der kontinuéierlecher Integratioun.
Optimisatioun vum Transpiléierungsprozess
Fir eng transpiléiert Liwwerung fir d'Produktioun ze generéieren, muss nëmmen de Code fir d'Produktioun ëmgewandelt ginn; Code nëmme fir Entwécklung gebraucht ka ginn iwwersprongen. Dat heescht, mir kënnen vermeiden all Tester (fir eise Projet a seng Ofhängegkeeten) an all Ofhängegkeete fir d'Entwécklung ze transpiléieren.
Wat Tester ugeet, wësse mer scho wou déi fir eise Projet stinn - zum Beispill ënnert dem Dossier tests/
. Mir mussen och erausfannen, wou déi fir d'Ofhängegkeete sinn - zum Beispill ënner hiren Ënnerdopper tests/
, test/
an Test/
(fir verschidde Bibliothéiken). Dann soen mir dem Rector fir dës Ordner ze veraarbecht:
return static function (ContainerConfigurator $containerConfigurator): void {
// ...
$parameters->set(Option::SKIP, [
// Skip tests
'*/tests/*',
'*/test/*',
'*/Test/*',
]);
};
Wat Ofhängegkeeten ugeet, weess de Komponist déi fir d'Entwécklung sinn (déi ënner der Entrée require-dev
in composer.json
) a wéi eng fir d'Produktioun sinn (déi ënner der Entrée require
).
Fir vum Composer d'Weeër vun all Ofhängegkeete fir d'Produktioun ze recuperéieren, lafe mir:
composer info --path --no-dev
Dëse Kommando wäert eng Lëscht vun Ofhängegkeeten mat hirem Numm a Wee produzéieren, sou:
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
Mir kënnen all d'Weeër extrahéieren an se an de Rektor Kommando fidderen, deen dann eise Projet veraarbecht src/
Dossier plus déi Ordner déi all Ofhängegkeete fir d'Produktioun enthalen:
$ paths="$(composer info --path --no-dev | cut -d' ' -f2- | sed 's/ //g' | tr 'n' ' ')"
$ vendor/bin/rector process src $paths
Eng weider Verbesserung kann verhënneren datt de Rector dës Ofhängegkeete veraarbecht déi scho mat der Zil-PHP Versioun benotzt. Wann eng Bibliothéik mat PHP 7.1 (oder all Versioun hei drënner) kodéiert gouf, da brauch se net op PHP 7.1 ze transpiléieren.
Fir dëst z'erreechen, kënne mir d'Lëscht vun de Bibliothéiken kréien, déi PHP 7.2 a méi erfuerderen an nëmmen déi veraarbecht. Mir kréien d'Nimm vun all dëse Bibliothéiken iwwer Composer's why-not
Kommando, esou:
composer why-not php "7.1.*" | grep -o "S*/S*"
Well dëst Kommando net mat der --no-dev
Fändel, fir nëmmen Ofhängegkeete fir d'Produktioun ze enthalen, musse mir fir d'éischt d'Ofhängegkeete fir d'Entwécklung erofhuelen an den Autoloader regeneréieren, de Kommando ausféieren an se dann erëm derbäi:
$ composer install --no-dev
$ packages=$(composer why-not php "7.1.*" | grep -o "S*/S*")
$ composer install
Komponist info --path
Kommando recuperéiert de Wee fir e Package, mat dësem Format:
# Executing this command
$ composer info psr/cache --path
# Produces this response:
psr/cache /Users/leo/GitHub/leoloso/PoP/vendor/psr/cache
Mir maachen dëst Kommando fir all Elementer an eiser Lëscht aus fir all Weeër ze kréien fir ze transpiléieren:
Braucht Dir eng Hosting-Léisung déi Iech e Konkurrenzvirdeel gëtt? BehmasterEt huet Iech mat onheemlecher Geschwindegkeet, moderner Sécherheet, an Auto-Scaling ofgedeckt. Kuckt eis Pläng
for package in $packages
do
path=$(composer info $package --path | cut -d' ' -f2-)
paths="$paths $path"
done
Schlussendlech gi mir dës Lëscht dem Rektor (plus dem Projet src/
Dossier):
vendor/bin/rector process src $paths
Falen ze vermeiden wann Dir Code transpiléiert
Transpiléiere vum Code kéint als Konscht ugesi ginn, déi dacks Tweaks erfuerderen spezifesch fir de Projet. Loosst eis e puer Probleemer gesinn, déi mir kënne kommen.
Kette Regele ginn net ëmmer veraarbecht
Eng Kette Regel ass wann eng Regel de Code muss konvertéieren, dee vun enger viregter Regel produzéiert gëtt.
Zum Beispill, Bibliothéik symfony/cache
enthält dëse Code:
final class CacheItem implements ItemInterface
{
public function tag($tags): ItemInterface
{
// ...
return $this;
}
}
Wann Dir vun PHP 7.4 op 7.3 transpiléiert, Funktioun tag
muss zwou Ännerunge maachen:
- De Retour Typ
ItemInterface
muss éischt ëmgerechent ginnself
, wéinst RegelDowngradeCovariantReturnTypeRector
- De Retour Typ
self
muss dann ewechgeholl ginn, wéinst RegelDowngradeSelfTypeDeclarationRector
D'Ennresultat sollt dëst sinn:
final class CacheItem implements ItemInterface
{
public function tag($tags)
{
// ...
return $this;
}
}
Wéi och ëmmer, de Rektor erausgëtt nëmmen déi Tëschenzäit:
final class CacheItem implements ItemInterface
{
public function tag($tags): self
{
// ...
return $this;
}
}
D'Fro ass, datt de Rektor net ëmmer d'Uerdnung kann kontrolléieren an där d'Regele applizéiert ginn.
D'Léisung ass z'identifizéieren wéi eng Kette Reegelen onveraarbecht gelooss goufen, an en neie Rector Run auszeféieren fir se anzesetzen.
Fir déi geketten Regelen z'identifizéieren, lafe mir de Rector zweemol um Quellcode, sou:
$ vendor/bin/rector process src
$ vendor/bin/rector process src --dry-run
Déi éischte Kéier lafe mir de Rector wéi erwaart, fir d'Transpilatioun auszeféieren. Déi zweete Kéier benotze mir de --dry-run
Fändel fir ze entdecken ob et nach Ännerunge musse gemaach ginn. Wann et ass, gëtt de Kommando mat engem Fehlercode erausgaang, an den "diff" Ausgang weist wéi eng Regel(en) nach ëmmer applizéiert kënne ginn. Dat géif heeschen datt den éischte Laf net fäerdeg war, mat enger chained Regel net veraarbecht ginn.
Wann mir déi net ugewandte Kette Regel (oder Regelen) identifizéiert hunn, kënne mir dann eng aner Rector Configuratiounsdatei erstellen - zum Beispill, rector-chained-rule.php
wäert déi fehlend Regel ausféieren. Amplaz e komplette Set vu Regele fir all Dateien ënner ze veraarbecht src/
, dës Kéier kënne mir déi spezifesch fehlend Regel op der spezifescher Datei lafen, wou se applizéiert muss ginn:
// rector-chained-rule.php
use RectorCoreConfigurationOption;
use RectorDowngradePhp74RectorClassMethodDowngradeSelfTypeDeclarationRector;
use SymfonyComponentDependencyInjectionLoaderConfiguratorContainerConfigurator;
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',
]);
};
Endlech soen mir dem Rector op sengem zweete Pass fir déi nei Configuratiounsdatei iwwer Input ze benotzen --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
Komponist Ofhängegkeete kënne inkonsistent sinn
Bibliothéike kënnen eng Ofhängegkeet deklaréieren fir d'Entwécklung (dh ënner require-dev
in composer.json
), awer ëmmer nach e puer Code vun hinnen fir d'Produktioun ze referenzéieren (wéi op e puer Dateien ënner src/
, net tests/
).
Normalerweis ass dëst kee Problem well dee Code vläicht net op der Produktioun gelueden gëtt, sou datt et ni e Feeler op der Applikatioun gëtt. Wéi och ëmmer, wann de Rector de Quellcode a seng Ofhängegkeeten veraarbecht, validéiert et datt all referenzéierte Code ka geluede ginn. De Rector wäert e Feeler werfen wann all Datei e Stéck Code vun enger net-installéierter Bibliothéik referéiert (well et deklaréiert gouf nëmme fir d'Entwécklung néideg ze sinn).
Zum Beispill, Klass EarlyExpirationHandler
vum Symfony's Cache Komponent implementéiert Interface MessageHandlerInterface
aus dem Messenger Komponent:
class EarlyExpirationHandler implements MessageHandlerInterface
{
//...
}
allerdéngs, symfony/cache
deklaréiert symfony/messenger
eng Ofhängegkeet fir Entwécklung ze sinn. Dann, wann Dir de Rector op engem Projet leeft, deen hänkt dovun of symfony/cache
, gëtt et e Feeler:
[ERROR] Could not process "vendor/symfony/cache/Messenger/EarlyExpirationHandler.php" file, due to:
"Analyze error: "Class SymfonyComponentMessengerHandlerMessageHandlerInterface not found.". Include your files in "$parameters->set(Option::AUTOLOAD_PATHS, [...]);" in "rector.php" config.
See https://github.com/rectorphp/rector#configuration".
Et ginn dräi Léisunge fir dëst Thema:
- An der Rector Config, sprang d'Veraarbechtung vun der Datei déi dat Stéck Code referéiert:
return static function (ContainerConfigurator $containerConfigurator): void {
// ...
$parameters->set(Option::SKIP, [
__DIR__ . '/vendor/symfony/cache/Messenger/EarlyExpirationHandler.php',
]);
};
- Luet déi fehlend Bibliothéik erof a füügt säi Wee derbäi fir vum Rektor automatesch gelueden ze ginn:
return static function (ContainerConfigurator $containerConfigurator): void {
// ...
$parameters->set(Option::AUTOLOAD_PATHS, [
__DIR__ . '/vendor/symfony/messenger',
]);
};
- Hutt Äre Projet ofhängeg vun der fehlend Bibliothéik fir d'Produktioun:
composer require symfony/messenger
Transpiléieren a kontinuéierlech Integratioun
Wéi virdru scho gesot, an eiser Entwécklungscomputer musse mir d' --dry-run
Fändel wann Dir Rector leeft, oder soss, gëtt de Quellcode mam transpiléierte Code iwwerschratt. Aus dësem Grond ass et méi gëeegent fir den aktuellen Transpiléierungsprozess wärend der kontinuéierlecher Integratioun (CI) auszeféieren, wou mir temporär Leefer kënne spinnen fir de Prozess auszeféieren.
Eng ideal Zäit fir den Transpiléierungsprozess auszeféieren ass wann Dir d'Verëffentlechung fir eise Projet generéiert. Zum Beispill, de Code hei ënnen ass e Workflow fir GitHub Actions, déi d'Verëffentlechung vun engem WordPress Plugin erstellt:
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/checkout@v2
- 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/action-zip@v0.1.0
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/upload-artifact@v2
with:
name: graphql-api
path: build/graphql-api.zip
- name: Upload to release
uses: JasonEtco/upload-to-release@master
with:
args: build/graphql-api.zip application/zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Dëse Workflow enthält eng Standardprozedur fir e WordPress Plugin iwwer GitHub Actions ze verëffentlechen. Déi nei Ergänzung, fir de Code vum Plugin vun PHP 7.4 op 7.1 ze transpiléieren, geschitt an dësem Schrëtt:
- 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
Zesummegefaasst mécht dësen Workflow elo déi folgend Schrëtt:
- Kontrolléiert de Quellcode fir e WordPress Plugin aus sengem Repository, geschriwwen mat PHP 7.4
- Installéiert seng Composer Ofhängegkeeten
- Transpiléiert säi Code vu PHP 7.4 op 7.1
- Ännert den "Verlaangt PHP" Entrée an der Haaptdatei vum Plugin Header vun
"7.4"
ze maachen"7.1"
- Entfernt d'Ofhängegkeete fir d'Entwécklung néideg
- Erstellt d'.zip Datei vum Plugin, ausser all onnéideg Dateien
- Eroplueden d'.zip Datei als Verëffentlechungsaktiv (an zousätzlech als Artefakt fir d'GitHub Action)
Testen de Transpiléierte Code
Wann de Code op PHP 7.1 transpiléiert ass, wéi wësse mir datt et gutt funktionnéiert? Oder, an anere Wierder, wéi wësse mir datt et grëndlech ëmgewandelt gouf, a keng Iwwerreschter vu méi héije Versioune vum PHP Code sinn hannerlooss?
Ähnlech wéi de Code transpiléieren, kënne mir d'Léisung an engem CI Prozess ëmsetzen. D'Iddi ass d'Ëmfeld vum Leefer mat PHP 7.1 opzestellen an e Linter op den transpiléierten Code auszeféieren. Wann e Stéck Code net kompatibel ass mat PHP 7.1 (wéi eng getippten Eegeschafte vu PHP 7.4 déi net ëmgewandelt gouf), da wäert d'Linter e Feeler werfen.
E Linter fir PHP dee gutt funktionnéiert ass PHP Parallel Lint. Mir kënnen dës Bibliothéik als Ofhängegkeet fir d'Entwécklung an eisem Projet installéieren, oder de CI-Prozess installéiere wéi e Standalone Composer-Projet:
composer create-project php-parallel-lint/php-parallel-lint
Wann ëmmer de Code PHP 7.2 a méi enthält, wäert PHP Parallel Lint e Feeler wéi dësen werfen:
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.
Loosst eis d'Linter an de Workflow vun eisem CI addéieren. D'Schrëtt fir auszeféieren fir Code vu PHP 8.0 op 7.1 ze transpiléieren an ze testen sinn:
- Kuckt de Quellcode aus
- Loosst d'Ëmfeld PHP 8.0 lafen, sou datt de Rector de Quellcode interpretéiere kann
- Transpiléiert de Code op PHP 7.1
- Installéiert de PHP Linter Tool
- Wiesselt d'PHP Versioun vun der Ëmwelt op 7.1
- Run der linter op der transpiled Code
Dëse GitHub Action Workflow mécht d'Aarbecht:
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/checkout@v2
- name: Set-up PHP
uses: shivammathur/setup-php@v2
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/setup-php@v2
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
Notéiert w.e.g. datt e puer bootstrap80.php
Dateien aus Symfony's Polyfill Bibliothéiken (déi net transpiléiert musse ginn) mussen aus der Linter ausgeschloss ginn. Dës Dateien enthalen PHP 8.0, sou datt d'Linter Feeler beim Veraarbechtung werfen. Wéi och ëmmer, dës Dateien auszeschléissen ass sécher well se nëmmen op der Produktioun gelueden ginn wann Dir PHP 8.0 oder méi leeft:
if (PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}
Resumé
Dësen Artikel huet eis geléiert wéi mir eise PHP Code transpiléiere kënnen, wat eis erlaabt PHP 8.0 am Quellcode ze benotzen an eng Verëffentlechung ze kreéieren déi op PHP 7.1 funktionnéiert. Transpiléiere gëtt iwwer Rector gemaach, e PHP Rekonstruktor Tool.
Eise Code transpiléieren mécht eis besser Entwéckler well mir Bugs an der Entwécklung besser kënne fangen a Code produzéieren deen natierlech méi einfach ass ze liesen a verstoen.
Transpiléieren erlaabt eis och eise Code mat spezifesche PHP Ufuerderunge vum CMS ofzekoppelen. Mir kënnen dat elo maachen wa mir wëllen déi lescht Versioun vu PHP benotzen fir en ëffentlech verfügbare WordPress Plugin oder Drupal Modul ze kreéieren ouni eis Userbase staark ze beschränken.
Hutt Dir Froen iwwer PHP transpiléieren? Loosst eis an der Kommentarsektioun wëssen!