PHP Kodunu Aktarmak için En İyi Kılavuz

Yayınlanan: 2021-09-22

İdeal koşullarda, tüm sitelerimiz için PHP 8.0'ı (bunu yazarken en son sürüm) kullanmalı ve yeni bir sürüm çıkar çıkmaz güncellemeliyiz. Bununla birlikte, geliştiricilerin, örneğin WordPress için genel bir eklenti oluştururken veya web sunucusunun ortamını yükseltmeyi engelleyen eski kodlarla çalışırken olduğu gibi, genellikle önceki PHP sürümleriyle çalışması gerekir.

Bu durumlarda, en son PHP kodunu kullanma umudumuzu yitirebiliriz. Ancak daha iyi bir alternatif var: Kaynak kodumuzu yine de PHP 8.0 ile yazabilir ve onu önceki bir PHP sürümüne, hatta PHP 7.1'e aktarabiliriz.

Bu kılavuzda, PHP kodunun aktarılması hakkında bilmeniz gereken her şeyi size öğreteceğiz.

Transpiling Nedir?

Aktarma, kaynak kodunu bir programlama dilinden aynı veya farklı bir programlama dilinin eşdeğer kaynak koduna dönüştürür.

Aktarma, web geliştirmede yeni bir kavram değildir: istemci tarafı geliştiriciler, JavaScript kodunun aktarıcısı olan Babel'e oldukça aşinadır.

Babel, JavaScript kodunu modern ECMAScript 2015+ sürümünden eski tarayıcılarla uyumlu eski bir sürüme dönüştürür. Örneğin, bir ES2015 ok işlevi verildiğinde:

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

…Babel onu ES5 versiyonuna dönüştürecek:

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

PHP'yi Aktarmak Nedir?

Web geliştirmede potansiyel olarak yeni olan şey, sunucu tarafı kodunun, özellikle PHP'nin aktarılması olasılığıdır.

PHP'yi aktarmak, JavaScript'i aktarmakla aynı şekilde çalışır: modern bir PHP sürümünün kaynak kodu, daha eski bir PHP sürümü için eşdeğer bir koda dönüştürülür.

Öncekiyle aynı örneği izleyerek, PHP 7.4'ten bir ok işlevi:

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

…eşdeğer PHP 7.3 sürümüne aktarılabilir:

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

Ok işlevleri, sözdizimsel şeker oldukları için aktarılabilir, yani mevcut bir davranışı üretmek için yeni bir sözdizimi. Bu düşük asılı meyvedir.

Bununla birlikte, yeni bir davranış yaratan yeni özellikler de vardır ve bu nedenle, PHP'nin önceki sürümleri için eşdeğer bir kod olmayacaktır. PHP 8.0'da tanıtılan birleşim türlerinde durum budur:

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

Bu durumlarda, yeni özellik geliştirme için gerekli olduğu, ancak üretim için gerekli olmadığı sürece aktarma hala yapılabilir. Ardından, ciddi sonuçlar olmadan özelliği aktarılan koddan tamamen kaldırabiliriz.

Böyle bir örnek sendika türleridir. Bu özellik, girdi türü ile sağlanan değer arasında herhangi bir uyumsuzluk olmadığını kontrol etmek için kullanılır, bu da hataların önlenmesine yardımcı olur. Eğer tiplerle bir çakışma varsa zaten geliştirme aşamasında olan bir hata olacaktır ve kod üretime ulaşmadan önce onu yakalayıp düzeltmeliyiz.

Bu nedenle, özelliği üretim kodundan kaldırmayı göze alabiliriz:

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

Hata üretimde devam ederse, atılan hata mesajı, birleşim türlerine sahip olduğumuzdan daha az kesin olacaktır. Ancak, bu potansiyel dezavantaj, ilk etapta birleşim tiplerinin kullanılabilmesi nedeniyle ağır basmaktadır.

Mükemmel bir dünyada, PHP 8.0'ı tüm sitelerimizde kullanabilmeli ve yeni bir sürüm çıkar çıkmaz güncelleyebilmeliyiz Ama durum her zaman böyle olmuyor. PHP kodunun aktarılması hakkında bilmeniz gereken her şeyi buradan öğrenin Tweetlemek için tıklayın

PHP Kodunu Aktarmanın Avantajları

Aktarma, bir kişinin PHP'nin en son sürümünü kullanarak bir uygulamayı kodlamasını ve PHP'nin eski sürümlerini çalıştıran ortamlarda da çalışan bir sürüm oluşturmasını sağlar.

Bu, özellikle eski içerik yönetim sistemleri (CMS) için ürünler oluşturan geliştiriciler için yararlı olabilir. Örneğin WordPress, resmi olarak PHP 5.6'yı desteklemektedir (PHP 7.4+ önermesine rağmen). PHP'nin 5.6 ila 7.2 sürümlerini çalıştıran WordPress sitelerinin yüzdesi – bunların tümü Kullanım Ömrü Sonu (EOL), yani artık güvenlik güncellemeleri almıyorlar – oldukça büyük bir yüzde 34,8 ve bunun dışında herhangi bir PHP sürümünde çalışan siteler. 8.0, yüzde 99,5 gibi büyük bir oranda duruyor:

Sürüme göre WordPress kullanımı
Sürüme göre WordPress kullanım istatistikleri. Resim kaynağı: WordPress

Sonuç olarak, küresel bir kitleyi hedefleyen WordPress temaları ve eklentileri, olası erişimlerini artırmak için büyük olasılıkla eski bir PHP sürümüyle kodlanacaktır. Aktarma sayesinde, bunlar PHP 8.0 kullanılarak kodlanabilir ve yine de daha eski bir PHP sürümü için yayınlanabilir, böylece mümkün olduğu kadar çok kullanıcı hedeflenebilir.

Gerçekten de, en son sürüm dışında herhangi bir PHP sürümünü desteklemesi gereken herhangi bir uygulama (şu anda desteklenen PHP sürümleri aralığında bile) yararlanabilir.

PHP 7.3 gerektiren Drupal'da durum böyledir. Aktarma sayesinde, geliştiriciler PHP 8.0 kullanarak herkese açık Drupal modülleri oluşturabilir ve bunları PHP 7.3 ile yayınlayabilir.

Başka bir örnek, PHP 8.0'ı bir nedenden dolayı kendi ortamlarında çalıştıramayan istemciler için özel kod oluştururken verilebilir. Yine de aktarma sayesinde geliştiriciler çıktılarını PHP 8.0 kullanarak kodlayabilir ve bu eski ortamlarda çalıştırabilir.

PHP Ne Zaman Aktarılmalı?

PHP kodu, önceki PHP sürümünde eşdeğeri olmayan bir PHP özelliği içermediği sürece her zaman aktarılabilir.

PHP 8.0'da tanıtılan özniteliklerle ilgili durum muhtemelen budur:

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

Ok işlevlerini kullanan önceki örnekte, ok işlevleri sözdizimsel şeker olduğundan kod aktarılabilir. Nitelikler, aksine, tamamen yeni davranışlar yaratır. Bu davranış PHP 7.4 ve altı ile de yeniden oluşturulabilir, ancak yalnızca manuel olarak kodlanarak, yani bir araç veya sürece dayalı olarak otomatik olarak değil (AI bir çözüm sağlayabilir, ancak henüz orada değiliz).

#[Deprecated] gibi geliştirme kullanımına yönelik öznitelikler, birleşim türlerinin kaldırıldığı şekilde kaldırılabilir. Ancak, uygulamanın üretimdeki davranışını değiştiren nitelikler kaldırılamaz ve doğrudan aktarılamazlar.

Bugün itibariyle, hiçbir aktarıcı PHP 8.0 öznitelikleriyle kod alamaz ve eşdeğeri PHP 7.4 kodunu otomatik olarak üretemez. Sonuç olarak, PHP kodunuzun öznitelikleri kullanması gerekiyorsa, onu aktarmak zor veya olanaksız olacaktır.

Aktarılabilen PHP Özellikleri

Bunlar, şu anda aktarılabilen PHP 7.1 ve üzeri özelliklerdir. Kodunuz yalnızca bu özellikleri kullanıyorsa, aktarılan uygulamanızın çalışacağından emin olabilirsiniz. Aksi takdirde, aktarılan kodun hata üretip üretmeyeceğini değerlendirmeniz gerekir.

PHP Sürümü Özellikler
7.1 Her şey
7.2object türü
– parametre tipi genişletme
preg_match içinde PREG_UNMATCHED_AS_NULL bayrağı
7.3list() / dizi yıkımındaki referans atamaları ( foreach içi hariç — #4376)
– Esnek Heredoc ve Nowdoc sözdizimi
– İşlev çağrılarında sondaki virgül
set(raw)cookie $seçenek argümanını kabul eder
7.4 – Yazılan özellikler
– Ok fonksiyonları
– Boş birleştirme atama operatörü
– Dizilerin içinde paketin açılması
– Sayısal değişmez ayırıcı
– etiket isimleri dizisi ile strip_tags()
– kovaryant dönüş türleri ve kontravariant param türleri
8.0 – Birlik türleri
mixed sözde tip
static dönüş tipi
::class sihirli sabiti
- ifadeleri match
– istisnaları yalnızca türe göre catch
– Sıfır güvenli operatör
– Sınıf kurucu mülk promosyonu
– Parametre listelerinde ve kapatma use listelerinde sondaki virgüller

PHP Aktarıcıları

Şu anda PHP kodunu aktarmak için bir araç var: Rector.

Rector, PHP kodunu programlanabilir kurallara göre dönüştüren bir PHP yeniden yapılandırma aracıdır. Kaynak kodu ve çalıştırılacak kurallar kümesini giriyoruz ve Rektör kodu dönüştürecek.

Rektör, Composer üzerinden projeye yüklenen komut satırı üzerinden çalıştırılır. Yürütüldüğünde, Rektör, dönüştürmeden önce ve sonra kodun bir "farkını" (eklemeler yeşil, çıkarmalar kırmızı) verir:

Rektörden "fark" çıktısı
Rektörden “fark” çıktısı

PHP'nin Hangi Sürümüne Aktarılacak

Kodu PHP sürümleri arasında aktarmak için ilgili kurallar oluşturulmalıdır.

Bugün, Rector kitaplığı, PHP 8.0 ila 7.1 aralığında kod aktarma kurallarının çoğunu içerir. Bu nedenle, PHP kodumuzu 7.1 sürümüne kadar güvenilir bir şekilde aktarabiliriz.

PHP 7.1'den 7.0'a ve 7.0'dan 5.6'ya aktarım için de kurallar vardır, ancak bunlar ayrıntılı değildir. Bunları tamamlamak için çalışmalar devam ediyor, bu nedenle sonunda PHP kodunu 5.6 sürümüne aktarabiliriz.

Aktarma vs Backporting

Backporting, aktarmaya benzer, ancak daha basittir. Backporting kodu, mutlaka bir dildeki yeni özelliklere dayanmaz. Bunun yerine, aynı işlevsellik, dilin yeni sürümünden ilgili kodu kopyalayarak/yapıştırarak/uyarlayarak dilin eski bir sürümüne sağlanabilir.

Örneğin, str_contains işlevi PHP 8.0'da tanıtıldı. PHP 7.4 ve altı için aynı işlev şu şekilde kolayca uygulanabilir:

 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 aktarmadan daha basit olduğu için, backporting işi ne zaman yaparsa yapsın bu çözümü seçmeliyiz.

PHP 8.0 ile 7.1 arasındaki aralıkla ilgili olarak, Symfony'nin çoklu doldurma kitaplıklarını kullanabiliriz:

  • Çoklu Doldurma PHP 7.1
  • Çoklu Doldurma PHP 7.2
  • Çoklu Doldurma PHP 7.3
  • Çoklu Doldurma PHP 7.4
  • Çoklu Doldurma PHP 8.0

Bu kitaplıklar aşağıdaki işlevleri, sınıfları, sabitleri ve arabirimleri destekler:

PHP Sürümü Özellikler
7.2 Fonksiyonlar:
  • spl_object_id
  • utf8_encode
  • utf8_decode

sabitler:

  • PHP_FLOAT_*
  • PHP_OS_FAMILY
7.3 Fonksiyonlar:
  • array_key_first
  • array_key_last
  • hrtime
  • is_countable

İstisnalar:

  • JsonException
7.4 Fonksiyonlar:
  • get_mangled_object_vars
  • mb_str_split
  • password_algos
8.0 Arayüzler:
  • Stringable

Sınıflar:

  • ValueError
  • UnhandledMatchError

sabitler:

  • FILTER_VALIDATE_BOOL

Fonksiyonlar:

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

Aktarılan PHP Örnekleri

Aktarılan PHP kodunun birkaç örneğini ve tamamen aktarılan birkaç paketi inceleyelim.

PHP Kodu

match ifadesi PHP 8.0'da tanıtıldı. Bu kaynak kodu:

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

switch operatörü kullanılarak eşdeğer PHP 7.4 sürümüne aktarılacaktır:

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

nullsafe operatörü PHP 8.0'da da tanıtıldı:

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

İşlemin iki kez yürütülmesini önlemek için, aktarılan kodun önce işlemin değerini yeni bir değişkene ataması gerekir:

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

PHP 8.0'da da tanıtılan yapıcı özelliği yükseltme özelliği, geliştiricilerin daha az kod yazmasına olanak tanır:

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

PHP 7.4 için aktarırken, tam kod parçası üretilir:

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

Yukarıdaki aktarılan kod, PHP 7.4'te tanıtılan, yazılan özellikleri içerir. Bu kodu PHP 7.3'e aktarmak, onları docblock'larla değiştirir:

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

PHP Paketleri

Aşağıdaki kitaplıklar üretim için aktarılıyor:

kitaplık/açıklama kod/notlar
rektör
Aktarmayı mümkün kılan PHP yeniden yapılandırma aracı
- Kaynak kodu
– Aktarılan kod
– Notlar
Kolay Kodlama Standartları
PHP kodunun bir dizi kurala uymasını sağlayan araç
- Kaynak kodu
– Aktarılan kod
– Notlar
WordPress için GraphQL API'si
WordPress için bir GraphQL sunucusu sağlayan eklenti
- Kaynak kodu
– Aktarılan kod
– Notlar

PHP'yi Aktarmanın Artıları ve Eksileri

PHP'yi aktarmanın faydası daha önce açıklanmıştır: kaynak kodun PHP 8.0'ı (yani PHP'nin en son sürümü) kullanmasına izin verir; bu, üretimin eski bir uygulama veya ortamda çalışması için PHP için daha düşük bir sürüme dönüştürülecektir.

Bu, etkili bir şekilde daha iyi geliştiriciler olmamızı ve daha yüksek kalitede kod üretmemizi sağlar. Bunun nedeni, kaynak kodumuzun PHP 8.0'ın birleşim türlerini, PHP 7.4'ün yazılan özelliklerini ve PHP'nin her yeni sürümüne eklenen farklı türleri ve sözde türleri (PHP 8.0'dan mixed , PHP 7.2'den object ) kullanabilmesidir. PHP'nin diğer modern özellikleri.

Bu özellikleri kullanarak geliştirme sırasında hataları daha iyi yakalayabilir ve okunması daha kolay kod yazabiliriz.

Şimdi dezavantajlarına bir göz atalım.

Kodlanmalı ve Bakımı Yapılmalıdır

Rektör kodu otomatik olarak aktarabilir, ancak işlem, bizim özel kurulumumuzla çalışması için büyük olasılıkla bazı manuel girdiler gerektirecektir.

Üçüncü Taraf Kitaplıkları da Aktarılmalıdır

Bu, olası nedeni bulmak için kaynak kodlarını araştırmamız gerektiğinden, bunları aktarma hatalar ürettiğinde bir sorun haline gelir. Sorun çözülebilirse ve proje açık kaynak ise, bir çekme isteği göndermemiz gerekecek. Kütüphane açık kaynak değilse, bir barikat ile karşılaşabiliriz.

Kod Aktarılamadığında Rektör Bize Haber Vermiyor

Kaynak kodu PHP 8.0 öznitelikleri veya aktarılamayan başka bir özellik içeriyorsa, devam edemeyiz. Ancak Rektör bu durumu kontrol etmeyecek, bu yüzden manuel olarak yapmamız gerekiyor. Bu, kendi kaynak kodumuzla ilgili olarak büyük bir sorun olmayabilir, çünkü buna zaten aşinayız, ancak üçüncü taraf bağımlılıkları için bir engel haline gelebilir.

Hata Ayıklama Bilgileri Kaynak Kodu Değil, Aktarılan Kodu Kullanır

Uygulama, üretimde yığın izleme içeren bir hata mesajı ürettiğinde, satır numarası aktarılan kodu gösterecektir. Kaynak kodda karşılık gelen satır numarasını bulmak için aktarılandan orijinal koda geri dönüştürmemiz gerekiyor.

Aktarılan Kodun Öneki de Yazılmalıdır

Aktarılan projemiz ve ayrıca üretim ortamında kurulan diğer bazı kitaplıklar, aynı üçüncü taraf bağımlılığını kullanabilir. Bu üçüncü taraf bağımlılığı projemiz için aktarılacak ve orijinal kaynak kodunu diğer kitaplık için koruyacak. Bu nedenle, olası çakışmaları önlemek için aktarılan sürüme PHP-Scoper, Strauss veya başka bir araç aracılığıyla ön ek eklenmelidir.

Aktarma Sürekli Entegrasyon (CI) Sırasında Gerçekleşmeli

Aktarılan kod, doğal olarak kaynak kodu geçersiz kılacağından, aktarma işlemini geliştirme bilgisayarlarımızda çalıştırmamalıyız, aksi takdirde yan etkiler oluşturma riskiyle karşı karşıya kalırız. İşlemi bir CI çalıştırması sırasında çalıştırmak daha uygundur (aşağıda daha fazlası).

PHP Nasıl Aktarılır

İlk olarak, geliştirme için projemizde Rektörü kurmamız gerekiyor:

 composer require rector/rector --dev

Ardından, gerekli kural setlerini içeren projenin kök dizininde bir rector.php yapılandırma dosyası oluşturuyoruz. Kodu PHP 8.0'dan 7.1'e düşürmek için bu yapılandırmayı kullanıyoruz:

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

İşlemin beklendiği gibi yürütüldüğünden emin olmak için, işlenecek konumu/konumları ileterek (bu durumda, src/ klasörü altındaki tüm dosyalar) Rektörün process komutunu kuru modda çalıştırabiliriz:

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

Aktarmayı gerçekleştirmek için, dosyaları mevcut konumlarında değiştirecek olan Rector'un process komutunu çalıştırıyoruz:

 vendor/bin/rector process src

Lütfen dikkat: geliştirme bilgisayarlarımızda rector process çalıştırırsak, kaynak kodu src/ altında yerinde dönüştürülür. Ancak, kodu düşürürken kaynak kodu geçersiz kılmamak için dönüştürülen kodu farklı bir konumda üretmek istiyoruz. Bu nedenle, sürekli entegrasyon sırasında süreci çalıştırmak en uygunudur.

Aktarma Sürecini Optimize Etme

Üretim için aktarılmış bir teslimat oluşturmak için yalnızca üretim kodunun dönüştürülmesi gerekir; sadece geliştirme için gerekli olan kod atlanabilir. Bu, tüm testleri (hem projemiz hem de bağımlılıkları için) ve geliştirme için tüm bağımlılıkları aktarmaktan kaçınabileceğimiz anlamına gelir.

Testlerle ilgili olarak, projemiz için olanların nerede olduğunu zaten bileceğiz - örneğin, tests/ klasörü altında. Ayrıca, bağımlılıklar için olanların nerede olduğunu da bulmalıyız - örneğin, alt klasörleri olan tests/ , test/ ve Test/ (farklı kitaplıklar için). Ardından, Rektöre şu klasörleri işlemeyi atlamasını söyleriz:

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

Bağımlılıklarla ilgili olarak, Composer hangilerinin geliştirme için olduğunu ( composer.json require-dev girişi altındakiler) ve hangilerinin üretim için olduğunu (giriş altındakiler require ) bilir.

Composer'dan üretim için tüm bağımlılıkların yollarını almak için şunu çalıştırırız:

 composer info --path --no-dev

Bu komut, adları ve yolları ile aşağıdaki gibi bir bağımlılık listesi üretecektir:

 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

Tüm yolları ayıklayabilir ve bunları projemizin src/ klasörünü ve üretim için tüm bağımlılıkları içeren klasörleri işleyecek olan Rector komutuna besleyebiliriz:

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

Başka bir iyileştirme, Rector'un halihazırda hedef PHP sürümünü kullanan bu bağımlılıkları işlemesini engelleyebilir. Bir kitaplık PHP 7.1 (veya aşağıdaki herhangi bir sürüm) ile kodlanmışsa, onu PHP 7.1'e aktarmaya gerek yoktur.

Bunu başarmak için PHP 7.2 ve üstü gerektiren kitaplıkların listesini alabilir ve yalnızca bunları işleyebiliriz. Tüm bu kitaplıkların adlarını Composer'ın Why why-not komutuyla şu şekilde elde edeceğiz:

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

Bu komut --no-dev bayrağıyla çalışmadığından, yalnızca üretim için bağımlılıkları dahil etmek için, önce geliştirme bağımlılıklarını kaldırmamız ve otomatik yükleyiciyi yeniden oluşturmamız, komutu yürütmemiz ve sonra bunları yeniden eklememiz gerekir:

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

Composer'ın info --path komutu, bir paketin yolunu şu biçimde alır:

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

Aktarılacak tüm yolları elde etmek için listemizdeki tüm öğeler için bu komutu uygularız:

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

Son olarak, bu listeyi Rektör'e sunuyoruz (artı projenin src/ klasörü):

Size rekabet avantajı sağlayan bir barındırma çözümüne mi ihtiyacınız var? Kinsta sizi inanılmaz hız, son teknoloji güvenlik ve otomatik ölçeklendirme ile donattı. Planlarımıza göz atın

 vendor/bin/rector process src $paths

Kodu Aktarırken Kaçınılması Gereken Tuzaklar

Kod aktarma, genellikle projeye özel ince ayarlar gerektiren bir sanat olarak kabul edilebilir. Karşılaşabileceğimiz birkaç soruna bakalım.

Zincirleme Kurallar Her Zaman İşlenmez

Zincirleme kural, bir kuralın önceki bir kural tarafından üretilen kodu dönüştürmesi gerektiği zamandır.

Örneğin, symfony/cache kitaplığı şu kodu içerir:

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

PHP 7.4'ten 7.3'e aktarırken, işlev tag iki değişikliğe uğramalıdır:

  • ItemInterface dönüş türü, DowngradeCovariantReturnTypeRector kuralı nedeniyle önce self dönüştürülmelidir.
  • Daha sonra, DowngradeSelfTypeDeclarationRector kuralı nedeniyle self dönüş türü kaldırılmalıdır.

Nihai sonuç şu olmalıdır:

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

Ancak, Rektör yalnızca ara aşamanın çıktısını verir:

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

Sorun şu ki, Rektör her zaman kuralların uygulanma sırasını kontrol edemez.

Çözüm, hangi zincirleme kuralların işlenmeden bırakıldığını belirlemek ve bunları uygulamak için yeni bir Rektör çalıştırması yürütmektir.

Zincirleme kuralları tanımlamak için kaynak kodunda iki kez Rector çalıştırıyoruz, şöyle:

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

İlk defa, aktarmayı yürütmek için beklendiği gibi Rektör'ü çalıştırıyoruz. İkinci kez, yapılacak değişiklikler olup olmadığını keşfetmek için --dry-run bayrağını kullanırız. Varsa, komut bir hata koduyla çıkacaktır ve “diff” çıktısı hangi kuralın/kuralların hala uygulanabileceğini gösterecektir. Bu, bazı zincirleme kuralların işlenmediği ilk çalıştırmanın tamamlanmadığı anlamına gelir.

--dry-run bayrağıyla çalışan Rektör
–Dry-run bayrağı ile çalışan Rektör

Uygulanmamış zincirleme kuralı (veya kuralları) belirledikten sonra, başka bir Rector yapılandırma dosyası oluşturabiliriz - örneğin, rector-chained-rule.php eksik kuralı yürütecektir. src/ altındaki tüm dosyalar için tam bir kural kümesini işlemek yerine, bu sefer, uygulanması gereken belirli dosyada belirli eksik kuralı çalıştırabiliriz:

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

Son olarak, ikinci geçişinde Rector'a input --config aracılığıyla yeni yapılandırma dosyasını kullanmasını söyleriz:

 # 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

Besteci Bağımlılıkları Tutarsız Olabilir

Kitaplıklar, geliştirme için planlanacak bir bağımlılık bildirebilir (yani, composer.json içindeki request require-dev altında), ancak yine de, üretim için onlardan bazı kodlara başvururlar (örneğin, src/ altındaki bazı dosyalarda, tests/ değil).

Genellikle, bu bir sorun değildir çünkü bu kod üretime yüklenmeyebilir, bu nedenle uygulamada asla bir hata olmaz. Ancak, Rektör kaynak kodu ve bağımlılıklarını işlerken, başvurulan tüm kodların yüklenebileceğini doğrular. Herhangi bir dosya, kurulu olmayan bir kitaplıktan bir kod parçasına başvurursa, Rektör bir hata verir (çünkü yalnızca geliştirme için gerekli olduğu bildirilmiş).

Örneğin, Symfony'nin Cache bileşeninden EarlyExpirationHandler sınıfı, Messenger bileşeninden MessageHandlerInterface arabirimini uygular:

 class EarlyExpirationHandler implements MessageHandlerInterface { //... }

Ancak, symfony/cache , symfony/messenger geliştirme için bir bağımlılık olduğunu bildirir. Ardından, symfony/cache bağlı bir projede Rector çalıştırıldığında bir hata verir:

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

Bu sorunun üç çözümü var:

  1. Rector yapılandırmasında, o kod parçasına başvuran dosyayı işlemeyi atlayın:
 return static function (ContainerConfigurator $containerConfigurator): void { // ... $parameters->set(Option::SKIP, [ __DIR__ . '/vendor/symfony/cache/Messenger/EarlyExpirationHandler.php', ]); };
  1. Eksik kitaplığı indirin ve Rektör tarafından otomatik olarak yüklenecek yolunu ekleyin:
 return static function (ContainerConfigurator $containerConfigurator): void { // ... $parameters->set(Option::AUTOLOAD_PATHS, [ __DIR__ . '/vendor/symfony/messenger', ]); };
  1. Projenizin üretim için eksik kitaplığa bağlı olmasını sağlayın:
 composer require symfony/messenger

Aktarma ve Sürekli Entegrasyon

Daha önce bahsedildiği gibi, geliştirme bilgisayarlarımızda --dry-run bayrağını kullanmalıyız, aksi takdirde kaynak kodu aktarılan kodla geçersiz kılınır. Bu nedenle, süreci yürütmek için geçici koşucuları döndürebileceğimiz sürekli entegrasyon (CI) sırasında gerçek aktarma sürecini çalıştırmak daha uygundur.

Aktarma sürecini yürütmek için ideal bir zaman, projemiz için yayın oluştururken. Örneğin, aşağıdaki kod, bir WordPress eklentisinin sürümünü oluşturan GitHub Eylemleri için bir iş akışıdır:

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

Bu iş akışı, GitHub Eylemleri aracılığıyla bir WordPress eklentisini yayınlamak için standart bir prosedür içerir. Eklenti kodunu PHP 7.4'ten 7.1'e dönüştürmek için yapılan yeni ekleme bu adımda gerçekleşir:

 - 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

Birlikte ele alındığında, bu iş akışı şimdi aşağıdaki adımları gerçekleştirir:

  1. PHP 7.4 ile yazılmış bir WordPress eklentisinin kaynak kodunu deposundan kontrol eder
  2. Composer bağımlılıklarını yükler
  3. Kodunu PHP 7.4'ten 7.1'e aktarır
  4. Eklentinin ana dosyasının başlığındaki "PHP gerektirir" girişini "7.4" ten "7.1" e değiştirir
  5. Geliştirme için gereken bağımlılıkları kaldırır
  6. Tüm gereksiz dosyalar hariç tutularak eklentinin .zip dosyasını oluşturur
  7. .zip dosyasını bir yayın varlığı olarak (ve ayrıca GitHub Eylemine bir yapıt olarak) yükler

Aktarılan Kodun Test Edilmesi

Kod PHP 7.1'e aktarıldıktan sonra, bunun iyi çalıştığını nasıl bilebiliriz? Veya başka bir deyişle, tamamen dönüştürüldüğünü ve PHP kodunun daha yüksek sürümlerinin hiçbir kalıntısının geride kalmadığını nereden biliyoruz?

Kodu aktarmaya benzer şekilde, çözümü bir CI işlemi içinde uygulayabiliriz. Buradaki fikir, koşucunun ortamını PHP 7.1 ile kurmak ve aktarılan kod üzerinde bir linter çalıştırmaktır. Herhangi bir kod parçası PHP 7.1 ile uyumlu değilse (PHP 7.4'ten dönüştürülmemiş, yazılan bir özellik gibi), o zaman linter bir hata verecektir.

PHP için iyi çalışan bir linter, PHP Parallel Lint'tir. Bu kitaplığı projemizde geliştirme bağımlılığı olarak kurabilir veya CI sürecinin bağımsız bir Besteci projesi olarak kurmasını sağlayabiliriz:

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

Kod PHP 7.2 ve üzerini içerdiğinde, PHP Parallel Lint şuna benzer bir hata verir:

 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'mizin iş akışına linter ekleyelim. PHP 8.0'dan 7.1'e kod aktarmak ve test etmek için yürütülecek adımlar şunlardır:

  1. Kaynak kodunu kontrol edin
  2. Rektörün kaynak kodunu yorumlayabilmesi için ortamın PHP 8.0'ı çalıştırmasını sağlayın
  3. Kodu PHP 7.1'e aktarın
  4. PHP linter aracını kurun
  5. Ortamın PHP sürümünü 7.1 olarak değiştirin
  6. Aktarılan kodda linter'i çalıştırın

Bu GitHub Eylem iş akışı işi yapar:

 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

Lütfen Symfony'nin çoklu doldurma kitaplıklarından (aktarılması gerekmeyen) birkaç bootstrap80.php dosyasının linterden çıkarılması gerektiğine dikkat edin. Bu dosyalar PHP 8.0 içerir, bu nedenle linter bunları işlerken hata verir. Ancak, üretime yalnızca PHP 8.0 veya üzeri çalıştırıldığında yükleneceklerinden bu dosyaları hariç tutmak güvenlidir:

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

İster WordPress için genel bir eklenti oluşturuyor ister eski kodu güncelliyor olun, en son PHP sürümünü kullanmanın imkansız olmasının birçok nedeni vardır Bu kılavuzda aktarmanın nasıl yardımcı olabileceğini öğrenin Tweetlemek için Tıklayın

Özet

Bu makale bize PHP kodumuzu nasıl aktaracağımızı öğreterek kaynak kodda PHP 8.0 kullanmamıza ve PHP 7.1 üzerinde çalışan bir sürüm oluşturmamıza izin verdi. Aktarma, bir PHP yeniden yapılandırma aracı olan Rector aracılığıyla yapılır.

Geliştirme sırasındaki hataları daha iyi yakalayabileceğimiz ve doğal olarak okunması ve anlaşılması daha kolay kodlar üretebileceğimiz için kodumuzu aktarmak bizi daha iyi geliştiriciler yapar.

Aktarma ayrıca, kodumuzu CMS'den belirli PHP gereksinimleriyle ayırmamızı sağlar. Artık, kullanıcı tabanımızı ciddi şekilde kısıtlamadan herkese açık bir WordPress eklentisi veya Drupal modülü oluşturmak için PHP'nin en son sürümünü kullanmak istiyorsak bunu yapabiliriz.

PHP'yi aktarmakla ilgili herhangi bir sorunuz var mı? Yorumlar bölümünde bize bildirin!