26 Kasım 2020 tarihinde yayınlanan yeni sürümle birlikte PHP 7.4.13 sürümünden stabil PHP 8.0 sürümüne geçmiş olduk. Versiyon değişikliği major olduğu için bir çok yenilik ve iyileştirmeyi beraberinde getirdi.

PHP 7’de çalışan bir kodu PHP 8.0’a aktarmak çok zor olmasa da, daha eski versiyonlardan geçişler için daha fazla düzeltme yapmanız gerekebilir. Zira 8.0 versiyonunda artık yer almayan fonksiyon ve özelliklerin bir bölümü zaten 7.x sürümlerinde de kaldırılmış veya uyarı vermeye başlamıştı.

PHP 8 ile neler değişti?

PHP 8.0 sitesinde yer aldığı sırayla neler yeni bir bakalım. Türkçe karşılıkları hatalı olabilir, esasen bu tarz terimlerin orijinallerinin kullanılması bana daha doğru geliyor.

Adlandırılmış Değişkenler (Named Arguments)

Python’da kullandığımız ve çok büyük rahatlık sağlayan Adlandırılmış Değişkenler özelliği 8.0 versiyonu ile birlikte artık PHP içinde kullanılabilir.

Adlandırılmış değişkenler özelliği fonksiyonlara parametrelerin belirli bir sırayla gönderilmesi zorunluluğunu ortadan kaldırıp, adları ile gönderilmesini sağlıyor. Bu kodun okunurluk ve anlaşılırlığını arttırdığı gibi geliştiricinin işini de çok kolaylaştırıyor. (Beni çok mutlu eden bir gelişme oldu)

//Pozisyonlu değişkenler kullanma
array_fill(0, 100, 50);
//Adlandırılmış değişkenler kullanma
array_fill(start_index: 0, num: 100, value: 50);

Özellikler (Attributes)

Diğer dillerde Ek Açıklamalar (Annotations) olarak da bilinen Özellikler (Attributes) eski tip doc bloklarını ayrıştırmak zorunda kalmadan meta veriler eklemeye izin veriyor.

Eskiden PHP sadece string tipinde yorum bloklarına izin veriyordu. PHP topluluğu bu sorunu aşmak için yorumların içinde @pseudo karakterini kullanarak ayrıştırma yöntemleri geliştirmişti. PHP 8.0 Attribute özelliği ile birlikte bu soruna doğal bir çözüm getirmiş oldu.

class PostsController
{
    /**
     * @Route("/api/posts/{id}", methods={"GET"})
     */
    public function get($id) { /* ... */ }
}
class PostsController
{
    #[Route("/api/posts/{id}", methods: ["GET"])]
    public function get($id) { /* ... */ }
}

Kurucularda özellik tanımları – Constructor property promotion

İşte geliştiricilerin hayatını kolaylaştıracak, hem daha az hem de daha anlaşılır koda olanak sağlayan özelliklerden biri daha. PHP 8.0 ile birlikte oluşturduğumuz classların özelliklerini doğrudan kurucu (constructor) içerisinde tanımlayıp aynı zamanda başlangıç değerini de atayabiliyoruz.

Eskiden özellik tanımları, metod tanımlarının dışında, classın en başında yapılır, başlangıç değeri atanacaksa bu yine kurucu içerisinde yapılırdı. PHP 8.0 bu tanımlamayı kısaltsa da böyle yapılmasını mecburi kılmıyor. Eski kodlarınızı olduğu gibi bırakabilir, yeni kodlarınızda alıştığınız sistemde devam edebilirsiniz.

class Point {
  public float $x;
  public float $y;
  public float $z;

  public function __construct(
    float $x = 0.0,
    float $y = 0.0,
    float $z = 0.0
  ) {
    $this->x = $x;
    $this->y = $y;
    $this->z = $z;
  }
}
class Point {
  public function __construct(
    public float $x = 0.0,
    public float $y = 0.0,
    public float $z = 0.0,
  ) {}
}

Birleşik Değişken Tipleri (Union Types)

Yine işleri çok kolaylaştıracak bir özellik daha. Birden fazla tipe sahip olabilecek değişkenleri sadece PHPDoc yorumları ile değil, çalışma zamanında doğrulanacak doğal birleşik değişken tipi tanımları ile yapabileceğiz.,

class Number {
  /** @var int|float */
  private $number;

  /**
   * @param float|int $number
   */
  public function __construct($number) {
    $this->number = $number;
  }
}

new Number('NaN'); // Ok
class Number {
  public function __construct(
    private int|float $number
  ) {}
}

new Number('NaN'); // TypeError

Match İfadesi (Match Expression)

PHP 8.0 ile birlikte yukarıdakiler kadar büyük bir değişim olmasa da, gerekli durumlarda işleri kolaylaştıran match ifadesi artık kullanılabilir

Yeni match ifadesi switch’e çok benzer ve aşağıdaki özelliklere sahip:

  • Match bir ifadedir, sonucu bir değişkende saklanabilir veya döndürülebilir.
  • Match’in karşılıkları tek satır ifadeleri destekler ve break; kullanılması gerekmez.
  • Match katı (strict) tip karşılaştırma yapar.
switch (8.0) {
  case '8.0':
    $result = "Oh no!";
    break;
  case 8.0:
    $result = "This is what I expected";
    break;
}
echo $result;
//> Oh no!
echo match (8.0) {
  '8.0' => "Oh no!",
  8.0 => "This is what I expected",
};
//> This is what I expected

Nullsafe Operatorü (Nullsafe operator)

PHP 8.0’a eklenen bu özellikte geliştiricilerin işini çok kolaylaştıracak, gereksiz kod yığınlarını ortadan kaldıracak faydalı bir özellik. Artık Null koşulları için kontroller yazmak yerine yeni eklenen Nullsafe operatörünü kullanabiliyoruz. Zincir olarak kullanabileceğimiz bu operatör sayesinde zincirin bir yerinde NULL değeri dönüyorsa başlangıç değerimizde doğrudan NULL olacaktır.

$country =  null;

if ($session !== null) {
  $user = $session->user;

  if ($user !== null) {
    $address = $user->getAddress();
 
    if ($address !== null) {
      $country = $address->country;
    }
  }
}
$country = $session?->user?->getAddress()?->country;

Daha akıllı metin ve sayı karşılaştırmaları (Saner string to number comparisons)

Eski sürümlerde metin ve sayı tipinde iki değişken karşılaştırılırken, metin tipindeki değişkenin değeri sayıya çevriliyor ve karşılaştırma iki sayı arasında yapılıyordu. Bu da metin değişkenin içeriğinin gerçekten sayı olmadığı durumlarda hatalı sonuçlar verebiliyordu. PHP 8.0 versiyonu ile birlikte metin tipli değişkenin içeriği gerçekten bir sayı değilse, sayı tipindeki değişken metin türüne çevirilip iki metinin aynı olup olmadığı kontrol ediliyor.

0 == 'foobar' // true
0 == 'foobar' // false

Dikkat: PHP 7’nin bu şekilde karşılaştırma yapmasını kontrollerinizde bilinçli olarak kullanıyorsanız bu durum eski kodlarınızın hatalı çalışmasına neden olabilir.

Dahili fonksiyonlar için tutarlı hata türleri (Consistent type errors for internal functions)

PHP 8.0 ile birlikte dahili fonksiyonların çoğu gönderilen parametreler doğrulanamazsa hata istisnası (exception error) fırlatıyorlar.

strlen([]); // Warning: strlen() expects parameter 1 to be string, array given

array_chunk([], -1); // Warning: array_chunk(): Size parameter expected to be greater than 0
strlen([]); // TypeError: strlen(): Argument #1 ($str) must be of type string, array given

array_chunk([], -1); // ValueError: array_chunk(): Argument #2 ($length) must be greater than 0

Dikkat: Bu durum hataları nasıl karşıladığına bağlı olarak eski php versiyonlarında çalışan kodlarınızın düzgün çalışmasını engelleyebilir.

Just-In-Time Derlemesi (JIT) (Just-In-Time Compilation)

PHP 8, Function JIT ve Tracing JIT adında iki JIT derleme motoru sunuyor. Diğerine göre daha başarılı olan Tracing JIT karşılaştırmalarda 3 kat daha iyi performans gösterirken uzun işlem süreli bazı uygulamalarda 1,5 – 2 kat iyileşme sağlıyor. Normal uygulamalardaki performansı PHP 7.4 ile aynı seviyede.

Just-In-Time Derlemesi (JIT)

PHP 8, iki JIT derleme motoru sunuyor. Tracing JIT, ikisi arasında en yetenekli olanı. Karşılaştırmalarda yaklaşık 3 kat daha iyi performans ve uzun süre işlem yapan bazı uygulamalarda 1,5–2 kat iyileşme gösteriyor. Normal uygulamalarda performansı PHP 7.4 ile aynı.

JIT motorlarının JIT’siz PHP 8’e göre karşılaştırması

Mixed Tipi

Bazen bir fonksiyonun döndüreceği bir değer veya gönderilecek parametrenin tipi birden fazla olabiliyor. Aşağıdaki değişken tiplerinin tamamını içeren yeni mixed tipi php geliştiricileri için büyük kolaylık olacak.

array
bool
callable
int
float
null
object
resource
string
function foo(mixed $bar): mixed {}

Objeler üzerinde ::class özelliğinin kullanımı

Eskiden bir objenin sınıfını öğrenmek için get_class() metodunu çağırmak zorundaydık. Artık sınıfa $foo::class şeklinde doğrudan ulaşabiliyoruz.

Değişkensiz Hata Ayıklama (Non-capturing catches)

Eskiden catch bloğu ile hata ayıklama yaparken gönderilen hatayı kullanmasak bile bir değişkene atamamız gerekiyordu. PHP 8.0 ile birlikte bu zorunluluk ortadan kalktı.

try {
    // Something goes wrong
} catch (Exception $exception) {
    Log::error("Something went wrong");
}
try {
    // Something goes wrong
} catch (Exception) {
    Log::error("Something went wrong");
}

str_contains() fonksiyonu

Eskiden bir metin değişkenin içinde bir başka değişkeni ararken str_pos fonksiyonunu kullanırdık, artık bu ihtiyaca özel, doğru veya yanlış değeri döndüren str_contains() fonksiyonumuz var.

str_starts_with() ve str_ends_with()

Yukarıdaki örnekte olduğu gibi dolambaçlı yollarla bulmak yerine metin tipinde bir değişken, istenen bir metinle başlıyor veya bitiyor mu öğrenebileceğimiz, doğru veya yanlış değerini veren iki yeni fonksiyonumuz var.

Son Sözler

PHP 8 geliştiricilerin işlerini kolaylaştıracak, kodun okunurluğunu ve anlaşılırlığını artıracak bir çok yeni özellikle geliyor. Ben bu yazıda en önemli gördüğüm değişikliklere yer verdim, fakat bunlar dışında yapılan iyileştirme ve yeniliklerde var. PHP 8.0 sayfasında bütün bunları daha ayrıntılı olarak inceleyebilirsiniz.

PHP 8’e geçmeye karar verdiyseniz bu kararınızı bir süre ertelemenizi gerektirebilecek durumları da unutmayın. Paylaşımlı sunucu kullanıyorsanız servis sağlayıcınız tarafından PHP 8 seçeneğinin sunulması için beklemeniz gerekebilir. Daha da önemlisi PHP 7 için geliştirilmiş özel eklentiler kullanıyorsanız bunların PHP 8 sürümlerinin yayınlanması için de beklemeniz gerekebilir.

Eğer siz de benim gibi Phalcon Framework kullanıyorsanız PHP 8’e geçmek ve Phalcon’u PHP 7.4 ile uzantı olarak kullanmaya devam etmek arasında bir seçim yapmanız gerekecek. Keza Phalcon 4 sürümü PHP 8’le kullanılamazken, gelecekte yayınlanacak Phalcon 5 sürümü ise artık PHP uzantısı olarak yayınlanmayacak.

Bu Yazıda Yapılan Değişiklikler
  • 11.05.2022: Yazı özeti düzenlendi.