Wordpress

PHP кодын көшіруге арналған түпкілікті нұсқаулық

Оңтайлы жағдайда біз барлық сайттарымыз үшін PHP 8.0 (оны жазу кезіндегі соңғы нұсқасы) қолданып, жаңа нұсқасы шыққан бойда оны жаңартуымыз керек. Дегенмен, әзірлеушілерге WordPress үшін жалпыға қолжетімді плагин жасау немесе веб-сервердің ортасын жаңартуға кедергі келтіретін ескі кодпен жұмыс істеу сияқты алдыңғы PHP нұсқаларымен жиі жұмыс істеу қажет болады.

Мұндай жағдайларда біз соңғы PHP кодын пайдаланудан үміт үзуіміз мүмкін. Бірақ жақсырақ балама бар: біз әлі де бастапқы кодты PHP 8.0 арқылы жазып, оны бұрынғы PHP нұсқасына, тіпті PHP 7.1 нұсқасына көшіре аламыз.

Бұл нұсқаулықта біз сізге PHP кодын көшіру туралы білуіңіз керек барлық нәрсені үйретеміз.

Транспиляция дегеніміз не?

Transpiling бастапқы кодты бағдарламалау тілінен бірдей немесе басқа бағдарламалау тілінің баламалы бастапқы кодына түрлендіреді.

Транспиляция веб-әзірлеудегі жаңа тұжырымдама емес: клиенттік әзірлеушілер JavaScript коды үшін транспилер Babel-пен жақсы таныс болуы мүмкін.

Babel заманауи ECMAScript 2015+ нұсқасынан JavaScript кодын ескі браузерлермен үйлесімді ескі нұсқаға түрлендіреді. Мысалы, ES2015 көрсеткі функциясы берілген:

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

…Babel оны ES5 нұсқасына түрлендіреді:

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

PHP транспиляциясы дегеніміз не?

Веб-әзірлеудегі ықтимал жаңалық серверлік кодты, атап айтқанда PHP-ді көшіру мүмкіндігі болып табылады.

PHP транспиляциясы 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]
);

Көрсеткі функцияларын көшіруге болады, себебі олар синтаксистік қант, яғни бар әрекетті жасау үшін жаңа синтаксис. Бұл төмен ілулі жеміс.

Дегенмен, жаңа мінез-құлық жасайтын жаңа мүмкіндіктер де бар, сондықтан PHP алдыңғы нұсқалары үшін баламалы код болмайды. Бұл PHP 8.0-де енгізілген кәсіподақ түрлеріне қатысты:

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

Мұндай жағдайларда транспиляцияны жаңа мүмкіндік өндіру үшін емес, әзірлеу үшін қажет болғанша орындауға болады. Содан кейін біз күрделі салдарсыз функцияны ауыстырылған кодтан толығымен алып тастай аламыз.

Мұндай мысалдардың бірі одақ түрлері. Бұл мүмкіндік қателерді болдырмауға көмектесетін енгізу түрі мен оның берілген мәні арасында сәйкессіздіктің жоқтығын тексеру үшін пайдаланылады. Егер түрлермен қайшылық болса, әзірлеуде қате болады және код өндіріске жеткенге дейін оны тауып, түзетуіміз керек.

Демек, біз өндіріс кодынан мүмкіндікті алып тастай аламыз:

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

Егер қате өндірісте әлі орын алса, жіберілген қате туралы хабар бізде кәсіподақ түрлері болғанға қарағанда дәлірек болады. Дегенмен, бұл ықтимал кемшілік бірінші кезекте кәсіподақ түрлерін пайдалану мүмкіндігінен асып түседі.

Кемелді әлемде біз барлық сайттарымызда PHP 8.0-ді қолданып, жаңа нұсқасы шыққан бойда оны жаңартып отыруымыз керек 😌 Бірақ бұл әрдайым бола бермейді. PHP кодын көшіру туралы білуіңіз керек барлық нәрсені осы жерден біліңіз👇Tweet түймесін басыңыз

РНР кодын көшірудің артықшылықтары

Транспиляция PHP соңғы нұсқасын пайдаланып қолданбаны кодтауға және PHP ескі нұсқаларымен жұмыс істейтін орталарда да жұмыс істейтін шығарылымды шығаруға мүмкіндік береді.

Бұл бұрынғы мазмұнды басқару жүйелері (CMS) үшін өнімдер жасайтын әзірлеушілер үшін әсіресе пайдалы болуы мүмкін. Мысалы, WordPress әлі де ресми түрде PHP 5.6 нұсқасын қолдайды (ол PHP 7.4+ нұсқасын ұсынғанымен). PHP 5.6-дан 7.2-ге дейінгі нұсқаларымен жұмыс істейтін WordPress сайттарының пайызы — олардың барлығы қызмет ету мерзімі (EOL), яғни олар енді қауіпсіздік жаңартуларын қабылдамайды — айтарлықтай 34.8% құрайды және басқа кез келген PHP нұсқасында жұмыс істейтіндер. 8.0 үлкен 99.5% құрайды:

Нұсқа бойынша WordPress қолдануы
Нұсқа бойынша WordPress қолдану статистикасы. Сурет көзі: WordPress

Демек, ғаламдық аудиторияға бағытталған WordPress тақырыптары мен плагиндері олардың ықтимал қолжетімділігін арттыру үшін PHP-тің ескі нұсқасымен кодталған болуы мүмкін. Транспиляцияның арқасында оларды PHP 8.0 арқылы кодтауға болады және әлі де ескі PHP нұсқасы үшін шығарылуы мүмкін, осылайша мүмкіндігінше көп пайдаланушыларға бағытталған.

Шынында да, ең соңғы нұсқасынан басқа кез келген PHP нұсқасын қолдауы қажет кез келген қолданба (тіпті қазіргі уақытта қолдау көрсетілетін PHP нұсқаларының ауқымында) пайдалы болуы мүмкін.

Бұл PHP 7.3 нұсқасын қажет ететін Drupal бағдарламасына қатысты. Транспиляцияның арқасында әзірлеушілер PHP 8.0 арқылы жалпыға қолжетімді Drupal модульдерін жасай алады және оларды PHP 7.3 арқылы шығара алады.

Басқа мысал, бір немесе басқа себептерге байланысты орталарында PHP 8.0-ді іске қоса алмайтын клиенттер үшін теңшелетін кодты жасау. Дегенмен, транспиляцияның арқасында әзірлеушілер әлі де PHP 8.0 арқылы жеткізілімдерін кодтай алады және оларды бұрынғы орталарда іске қоса алады.

PHP қашан көшіру керек

РНР кодын бұрынғы PHP нұсқасында баламасы жоқ кейбір PHP мүмкіндігі болмаса, әрқашан көшіруге болады.

Бұл PHP 8.0-де енгізілген атрибуттарға қатысты болуы мүмкін:

#[SomeAttr]
function someFunc() {}

#[AnotherAttr]
class SomeClass {}

Көрсеткі функцияларын пайдаланатын алдыңғы мысалда кодты көшіруге болады, себебі көрсеткі функциялары синтаксистік қант болып табылады. Атрибуттар, керісінше, мүлдем жаңа мінез-құлық жасайды. Бұл әрекетті PHP 7.4 және одан төмен нұсқаларында да шығаруға болады, бірақ оны қолмен кодтау арқылы ғана, яғни құралға немесе процеске автоматты түрде негізделмейді (AI шешімді ұсына алады, бірақ біз әлі ол жерде емеспіз).

сияқты әзірлеуге арналған атрибуттар #[Deprecated], біріктіру түрлері жойылатын сияқты жойылуы мүмкін. Бірақ қолданбаның өндірістегі әрекетін өзгертетін атрибуттарды жою мүмкін емес және оларды тікелей көшіру де мүмкін емес.

Бүгінгі күні ешбір транспилер PHP 8.0 атрибуттары бар кодты қабылдай алмайды және оның баламалы PHP 7.4 кодын автоматты түрде жасай алмайды. Демек, егер сіздің PHP кодыңыз атрибуттарды пайдалану қажет болса, оны көшіру қиын немесе мүмкін емес болады.

Транспиляцияға болатын PHP мүмкіндіктері

Бұл қазіргі уақытта көшіруге болатын PHP 7.1 және одан жоғары нұсқалардың мүмкіндіктері. Егер сіздің кодыңыз тек осы мүмкіндіктерді пайдаланса, көшірілген қолданбаңыздың жұмыс істейтініне сенімді бола аласыз. Әйтпесе, ауыстырылған кодтың сәтсіздікке әкелетінін бағалау қажет болады.

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 кодын көшіруге арналған бір құрал бар: Ректор.

Ректор бағдарламаланатын ережелер негізінде РНР кодын түрлендіретін РНР реконструкция құралы болып табылады. Біз бастапқы кодты және орындалатын ережелер жинағын енгіземіз, ал ректор кодты түрлендіреді.

Ректор Композитор арқылы жобада орнатылған пәрмен жолы арқылы басқарылады. Орындалған кезде ректор түрлендіруге дейін және одан кейін кодтың «айырмашылығын» (қосулар жасыл түспен, алып тастау қызыл түспен) шығарады:

Ректордан «дифф» шығысы
Ректордан «айырма» шығысы

PHP қай нұсқасына көшіру керек

PHP нұсқалары бойынша кодты көшіру үшін сәйкес ережелерді жасау керек.

Бүгінгі таңда Ректор кітапханасы PHP 8.0-ден 7.1-ге дейінгі диапазондағы кодты көшіру ережелерінің көпшілігін қамтиды. Осылайша, біз PHP кодын 7.1 нұсқасына дейін сенімді түрде көшіре аламыз.

Сондай-ақ PHP 7.1-ден 7.0-ге және 7.0-ден 5.6-ға көшіру ережелері бар, бірақ олар толық емес. Оларды аяқтау бойынша жұмыс жүргізілуде, сондықтан PHP кодын 5.6 нұсқасына дейін көшіруіміз мүмкін.

Транспилинг пен Бэкпортинг

Бэкпортинг транспиляцияға ұқсас, бірақ қарапайым. Бекіту коды міндетті түрде тілдің жаңа мүмкіндіктеріне сүйенбейді. Оның орнына сол функционалдылықты тілдің жаңа нұсқасынан сәйкес кодты көшіру/қою/бейімдеу арқылы тілдің ескі нұсқасына беруге болады.

Мысалы, функция 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;
    }
  }
}

Өйткені бэкпортинг транспиляцияға қарағанда оңайырақ, біз бұл шешімді бэкпортинг тапсырманы орындаған кезде таңдауымыз керек.

PHP 8.0-ден 7.1-ге дейінгі диапазонға қатысты біз Symfony полифилл кітапханаларын пайдалана аламыз:

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

Бұл кітапханалар келесі функцияларды, сыныптарды, тұрақтыларды және интерфейстерді көрсетеді:

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 коды

The 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();
}

Транспиляцияланған код операцияны екі рет орындамау үшін алдымен жаңа айнымалыға операцияның мәнін тағайындауы керек:

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

PHP 8.0-де де енгізілген конструктор сипатын жылжыту мүмкіндігі әзірлеушілерге азырақ код жазуға мүмкіндік береді:

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

Оны PHP 7.4 нұсқасына көшіру кезінде кодтың толық бөлігі шығарылады:

 class QueryResolver
 {
  protected QueryFormatter $queryFormatter;

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

Жоғарыда көшірілген код PHP 7.4-те енгізілген терілген сипаттарды қамтиды. Бұл кодты PHP 7.3 нұсқасына көшіру оларды құжат блоктарымен ауыстырады:

 class QueryResolver
 {
  /**
   * @var QueryFormatter
   */
  protected $queryFormatter;

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

PHP пакеттері

Келесі кітапханалар өндіріске көшіріліп жатыр:

Кітапхана/сипаттама Код/ескертпелер
Ректор
Транспиляцияны мүмкін ететін PHP қайта құру құралы
- бастапқы код
– Транспиляцияланған код
– Ескертулер
Жеңіл кодтау стандарттары
РНР коды ережелер жинағына сәйкес келетін құрал
- бастапқы код
– Транспиляцияланған код
– Ескертулер
WordPress үшін GraphQL API
WordPress үшін GraphQL серверін қамтамасыз ететін плагин
- бастапқы код
– Транспиляцияланған код
– Ескертулер

РНР транспиляциясының жақсы және жағымсыз жақтары

PHP транспиляциясының артықшылығы қазірдің өзінде сипатталған: ол бастапқы кодқа PHP 8.0 (яғни PHP соңғы нұсқасы) пайдалануға мүмкіндік береді, ол бұрынғы қолданбада немесе ортада жұмыс істеу үшін өндіріс үшін PHP үшін төменгі нұсқаға түрлендіріледі.

Бұл бізге жоғары сапалы кодты шығара отырып, жақсы әзірлеушілер болуға тиімді мүмкіндік береді. Себебі, біздің бастапқы код PHP 8.0 біріктіру түрлерін, PHP 7.4 типтік сипаттарын және PHP бағдарламасының әрбір жаңа нұсқасына қосылған әртүрлі типтер мен псевдотиптерді пайдалана алады (mixed PHP 8.0 бастап, object PHP 7.2-ден), PHP-тің басқа заманауи мүмкіндіктерімен қатар.

Осы мүмкіндіктерді пайдалана отырып, біз әзірлеу кезінде қателерді жақсырақ анықтай аламыз және оқуға оңай кодты жаза аламыз.

Енді кемшіліктерді қарастырайық.

Ол кодталуы және сақталуы керек

Ректор кодты автоматты түрде ауыстыра алады, бірақ процесс оны біздің арнайы орнатуымызбен жұмыс істеуі үшін қолмен енгізуді қажет етуі мүмкін.

Үшінші тарап кітапханалары да көшірілуі керек

Бұл оларды көшіру қателер тудырған кезде мәселеге айналады, өйткені ықтимал себебін анықтау үшін олардың бастапқы кодын зерттеуіміз керек. Егер мәселе шешілсе және жоба ашық бастапқы код болса, тарту сұрауын жіберуіміз керек. Кітапхананың бастапқы көзі ашық болмаса, біз кедергіге тап болуымыз мүмкін.

Ректор кодты көшіру мүмкін болмаған кезде бізге хабар бермейді

Бастапқы кодта PHP 8.0 атрибуттары немесе көшіруге болмайтын кез келген басқа мүмкіндік болса, біз жалғастыра алмаймыз. Алайда ректор бұл жағдайды тексермейді, сондықтан оны қолмен жасау керек. Бұл біздің бастапқы кодымызға қатысты үлкен мәселе болмауы мүмкін, өйткені біз онымен бұрыннан таныспыз, бірақ ол үшінші тарап тәуелділіктеріне қатысты кедергі болуы мүмкін.

Түзету ақпараты бастапқы кодты емес, көшірілген кодты пайдаланады

Қолданба өндірісте стек ізі бар қате туралы хабарды шығарғанда, жол нөмірі транспиляцияланған кодты көрсетеді. Бастапқы кодтағы сәйкес жол нөмірін табу үшін көшірілген кодтан бастапқы кодқа қайта түрлендіру керек.

Транспиляцияланған код да префикс болуы керек

Біздің көшірілген жобамыз және өндіріс ортасында орнатылған кейбір басқа кітапхана бірдей үшінші тарап тәуелділігін пайдалана алады. Бұл үшінші тарап тәуелділігі жобамызға көшіріледі және басқа кітапхана үшін өзінің бастапқы бастапқы кодын сақтайды. Демек, ықтимал қақтығыстарды болдырмау үшін көшірілген нұсқаға PHP-Scoper, Strauss немесе басқа құрал арқылы префикс қою керек.

Үздіксіз интеграция (CI) кезінде транспиляция орын алуы керек

Транспиляцияланған код бастапқы кодты табиғи түрде қайта анықтайтындықтан, өңдеу компьютерлерімізде көшіру процесін іске қоспауымыз керек, әйтпесе жанама әсерлерді жасау қаупі бар. Процесті CI іске қосу кезінде іске қосу қолайлырақ (бұл туралы толығырақ төменде).

PHP қалай көшіруге болады

Біріншіден, әзірлеу үшін жобамызға ректорды орнату керек:

composer require rector/rector --dev

Содан кейін біз a rector.php қажетті ережелер жиынын қамтитын жобаның түбірлік каталогындағы конфигурация файлы. Кодты PHP 8.0-ден 7.1-ге дейін төмендету үшін біз мына конфигурацияны қолданамыз:

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);
};

Процестің күтілгендей орындалатынына көз жеткізу үшін біз ректорды іске қоса аламыз process пәрмен құрғақ режимде өңделетін орын(дарды) береді (бұл жағдайда қалта астындағы барлық файлдар src/):

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

Транспильді орындау үшін біз ректордың жұмысын жүргіземіз process файлдарды олардың бар орнында өзгертетін пәрмен:

vendor/bin/rector process src

Назар аударыңыз: егер біз жүгірсек rector process әзірлеуші ​​компьютерлерімізде бастапқы код орнына, астында түрлендіріледі src/. Дегенмен, кодты төмендеткен кезде бастапқы кодты қайталамау үшін түрлендірілген кодты басқа жерде шығарғымыз келеді. Осы себепті процесті іске қосу үздіксіз интеграция кезінде ең қолайлы.

Транспиляция процесін оңтайландыру

Өндіріс үшін транспильді жеткізуді жасау үшін тек өндіріс коды түрлендірілуі керек; әзірлеу үшін ғана қажет кодты өткізіп жіберуге болады. Бұл біз барлық сынақтарды (біздің жобамыз үшін де, оның тәуелділіктері үшін де) және әзірлеуге арналған барлық тәуелділіктерді ауыстырудан аулақ бола аламыз дегенді білдіреді.

Тесттерге келетін болсақ, біз жобамыздың қай жерде орналасқанын білеміз, мысалы, қалта астында tests/. Біз сондай-ақ тәуелділіктердің қай жерде екенін білуіміз керек - мысалы, олардың ішкі қалталарының астында tests/, test/ және Test/ (әртүрлі кітапханалар үшін). Содан кейін біз ректорға мына қалталарды өңдеуді өткізіп жіберуді айтамыз:

return static function (ContainerConfigurator $containerConfigurator): void {
  // ...

  $parameters->set(Option::SKIP, [
    // Skip tests
    '*/tests/*',
    '*/test/*',
    '*/Test/*',
  ]);
};

Тәуелділіктерге келетін болсақ, композитор олардың қайсысын дамытуға арналғанын біледі (енгізілгендер require-dev in composer.json) және қайсысы өндіріске арналған (енгізілгендер require).

Композитордан өндіріске арналған барлық тәуелділіктердің жолдарын шығарып алу үшін біз келесі әрекеттерді орындаймыз:

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

Біз барлық жолдарды шығарып, оларды Ректор пәрменіне бере аламыз, содан кейін ол біздің жобаны өңдейді src/ қалта және өндіріске барлық тәуелділіктерді қамтитын қалталар:

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

Әрі қарай жақсарту ректордың мақсатты PHP нұсқасын пайдаланып, сол тәуелділіктерді өңдеуіне кедергі келтіруі мүмкін. Кітапхана PHP 7.1 (немесе төмендегі кез келген нұсқа) арқылы кодталған болса, оны PHP 7.1 нұсқасына көшірудің қажеті жоқ.

Бұған қол жеткізу үшін біз PHP 7.2 және одан жоғары нұсқасын талап ететін кітапханалар тізімін алып, соларды ғана өңдей аламыз. Біз бұл кітапханалардың барлығының атауларын Composer's арқылы аламыз why-not бұйрық, келесідей:

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

Транспиляцияның барлық жолдарын алу үшін тізімдегі барлық элементтер үшін осы пәрменді орындаймыз:

Сізге бәсекеге қабілеттілік беретін хостинг шешімі керек пе? Behmasterол сізді керемет жылдамдықпен, ең соңғы қауіпсіздікпен және автоматты масштабтаумен қамтыды. Біздің жоспарларымызды тексеріңіз

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

Соңында біз бұл тізімді ректорға береміз (плюс жобаның src/ қалта):

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;
  }
}

Мәселе мынада, ректор әрқашан ережелерді қолдану тәртібін бақылай алмайды.

Шешім - қандай тізбектелген ережелер өңделмей қалғанын анықтау және оларды қолдану үшін жаңа ректорды орындау.

Тізбектелген ережелерді анықтау үшін біз бастапқы кодта ректорды екі рет іске қосамыз, мысалы:

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

Бірінші рет транспиляцияны орындау үшін біз ректорды күткендей басқардық. Екінші рет қолданамыз --dry-run әлі де енгізілетін өзгерістер бар-жоғын анықтау үшін жалауша. Егер бар болса, пәрмен қате кодымен шығады және «айырма» шығысы қай ереже(лер) әлі де қолданылуы мүмкін екенін көрсетеді. Бұл бірінші іске қосудың аяқталмағанын, кейбір тізбектелген ережелер өңделмегенін білдіреді.

--dry-run жалаушасымен жұмыс істейтін ректор
– Құрғақ жұмыс жалауымен жұмыс істейтін ректор

Қолданбаған тізбектелген ережені (немесе ережелерді) анықтағаннан кейін, біз басқа Ректор конфигурация файлын жасай аламыз, мысалы, rector-chained-rule.php жетіспейтін ережені орындайды. Төмендегі барлық файлдар үшін ережелердің толық жинағын өңдеудің орнына src/, бұл жолы біз арнайы жетіспейтін ережені қолдану керек жерде нақты файлда іске қоса аламыз:

// 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',
  ]);
};

Соңында біз ректорға екінші рұқсатта жаңа конфигурация файлын енгізу арқылы пайдалануды айтамыз --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 in composer.json), дегенмен, өндіріс үшін олардың кейбір кодтарына сілтеме жасаңыз (мысалы, астындағы кейбір файлдарда src/емес, tests/).

Әдетте, бұл мәселе емес, себебі бұл код өндірісте жүктелмеуі мүмкін, сондықтан қолданбада ешқашан қате болмайды. Дегенмен, Ректор бастапқы кодты және оның тәуелділіктерін өңдегенде, ол барлық сілтеме жасалған кодты жүктеуге болатынын растайды. Кез келген файл орнатылмаған кітапхананың кейбір код бөлігіне сілтеме жасаса, ректор қате жібереді (өйткені ол тек әзірлеу үшін қажет деп жарияланған).

Мысалы, сынып EarlyExpirationHandler Symfony компаниясының Cache компонентінен интерфейсті жүзеге асырады MessageHandlerInterface Messenger компонентінен:

class EarlyExpirationHandler implements MessageHandlerInterface
{
    //...
}

Алайда, symfony/cache жариялады symfony/messenger дамуға тәуелді болу. Содан кейін, тәуелді жобада ректорды іске қосқанда symfony/cache, ол қате жібереді:

[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".   

Бұл мәселенің үш шешімі бар:

  1. Ректор конфигурациясында осы код бөлігіне сілтеме жасайтын файлды өңдеуді өткізіп жіберіңіз:
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

Транспиляция және үздіксіз интеграция

Жоғарыда айтылғандай, компьютерлерді әзірлеуде біз пайдалануымыз керек --dry-run Rektor іске қосылған кезде жалауша немесе басқа жағдайда бастапқы код көшірілген кодпен қайта анықталады. Осы себепті, процесті орындау үшін уақытша жүгірушілерді айналдыра алатын үздіксіз интеграция (CI) кезінде нақты транспиляция процесін іске қосу қолайлырақ.

Транспиляция процесін орындаудың тамаша уақыты - жобамыз үшін шығарылымды жасау. Мысалы, төмендегі код WordPress плагинінің шығарылымын жасайтын GitHub Actions үшін жұмыс процесі болып табылады:

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 }}

Бұл жұмыс үрдісінде GitHub әрекеттері арқылы WordPress плагинін шығарудың стандартты процедурасы бар. Плагин кодын 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. PHP 7.4 нұсқасымен жазылған WordPress плагинінің бастапқы кодын оның репозиторийінен тексереді
  2. Композитор тәуелділіктерін орнатады
  3. Өз кодын PHP 7.4-тен 7.1-ге ауыстырады
  4. Плагиннің негізгі файлының тақырыбындағы «PHP талап етеді» жазбасын келесіден өзгертеді "7.4" дейін "7.1"
  5. Дамыту үшін қажетті тәуелділіктерді жояды
  6. Барлық қажет емес файлдарды қоспағанда, плагиннің .zip файлын жасайды
  7. .zip файлын шығарылым активі ретінде жүктеп салады (және оған қоса, GitHub әрекетіне артефакт ретінде)

Транспиляцияланған кодты сынау

Код PHP 7.1 нұсқасына көшірілгеннен кейін оның жақсы жұмыс істейтінін қайдан білеміз? Немесе, басқаша айтқанда, оның мұқият түрлендірілгенін және PHP кодының жоғарырақ нұсқаларының қалдықтары қалмағанын қайдан білеміз?

Кодты көшіру сияқты, біз шешімді CI процесінде жүзеге асыра аламыз. Идея – жүгіруші ортасын PHP 7.1 нұсқасымен орнату және көшірілген кодта линтерді іске қосу. Егер кодтың кез келген бөлігі PHP 7.1 нұсқасымен үйлесімді болмаса (мысалы, түрлендірілмеген PHP 7.4 нұсқасынан терілген сипат), онда линтер қате жібереді.

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.

Линтерді CI жұмыс процесіне қосайық. PHP 8.0-ден 7.1-ге көшіру кодын орындау және оны тексеру қадамдары:

  1. Бастапқы кодты тексеріңіз
  2. Ортаны PHP 8.0 іске қосыңыз, сондықтан ректор бастапқы кодты түсіндіре алады
  3. Кодты PHP 7.1 нұсқасына көшіріңіз
  4. PHP линтер құралын орнатыңыз
  5. Ортаның PHP нұсқасын 7.1 нұсқасына ауыстырыңыз
  6. Транспиляцияланған кодта линтерді іске қосыңыз

Бұл GitHub әрекетінің жұмыс процесі келесі тапсырманы орындайды:

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

Назар аударыңыз, бірнеше bootstrap80.php Symfony полифилл кітапханаларындағы файлдар (оларды көшіруді қажет етпейтін) линтерден шығарылуы керек. Бұл файлдарда PHP 8.0 бар, сондықтан оларды өңдеу кезінде линтер қателер жібереді. Дегенмен, бұл файлдарды алып тастау қауіпсіз, өйткені олар PHP 8.0 немесе одан жоғары нұсқасын іске қосқан кезде ғана өндірісте жүктеледі:

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

WordPress үшін жалпыға қолжетімді плагин жасап жатырсыз ба немесе ескі кодты жаңартып жатсаңыз да, соңғы PHP нұсқасын пайдалану мүмкін болмайтын көптеген себептер бар 👩‍💻 Транспиляция қалай көмектесетінін осы нұсқаулықтан біліңіз👇Tweet түймесін басыңыз

қысқаша мазмұндама

Бұл мақала бізге PHP кодын қалай көшіру керектігін үйретті, бұл PHP 8.0-ді бастапқы кодта пайдалануға және PHP 7.1-де жұмыс істейтін шығарылымды жасауға мүмкіндік береді. Транспиляция PHP реконструкция құралының Rector арқылы жүзеге асырылады.

Біздің кодты көшіру бізді жақсы әзірлеушілерге айналдырады, өйткені біз әзірлеудегі қателерді жақсырақ анықтай аламыз және оқуға және түсінуге оңай кодты жасай аламыз.

Транспиляция сонымен қатар кодымызды CMS-тен PHP-нің арнайы талаптарымен ажыратуға мүмкіндік береді. Пайдаланушылар базасын қатаң шектемей, жалпыға қолжетімді WordPress плагинін немесе Drupal модулін жасау үшін PHP-тің соңғы нұсқасын қолданғымыз келсе, енді мұны істей аламыз.

PHP транспиляциясы туралы сұрақтарыңыз бар ма? Түсініктеме бөлімінде бізге хабарлаңыз!

Қатысты Мақалалар

пікір қалдыру

Сіздің электрондық пошта мекенжайы емес жарияланады.

Басына оралу