PHP 8'e Hızlı Bakış

İzni Burak Demirtaş
8 min readJun 15, 2020

Merhabalar. PHP 8 ile birlikte hayatımıza neler gelecek, neler değişecek birlikte göz atmaya var mısınız? Haydi başlayalım o zaman…

Son güncelleme tarihi: 3 Eylül 2020
Bu tarihten sonra RFC’lerde yapılan eklemeler ve güncellemelere göre yeni özellikler gelmiş veya belirtilmiş özellikler için değişiklikler olmuş olabilir. Fırsatım olduğunca güncelliği korumaya çalışıyorum ama en güncel bilgiler için RFC tartışmalarının bulunduğu kaynakları takip edebilirsiniz.
(Yazının en altında linkleri yazdım)

PHP 8'in, bu yılın son aylarında çıkması bekleniyor. Şimdilik beklenen tarih 26 Kasım 2020. Bu versiyon ile birlikte bir çok yeni özellik ve performans iyileştirmeleri sunulacak. Şu sıralarda da aktif bir şekilde geliştirmeler devam ediyor ve önümüzdeki günlerde Alpha versiyonlar yayınlanmaya başlanacak. Heyecanlı ve meraklıyız.

Peki ne gibi yeni özellikler gelecek? Neler değişecek? Hangi özelliklere veda edeceğiz? Şimdi biraz da bunlara göz atmaya çalışalım. Tüm detaylara girmeyeceğim ama, olabildiğince en öne çıkan maddelere değineceğim.

Union Types

En etkili ve kullanışlı yeniliklerden biri Union Types olacak gibi duruyor. Artık değişken, parametre veya dönüş tipi belirtirken çoklu olarak yazabileceğiz. Şu örneği inceleyebiliriz:

public function foo(Foo|Bar $input): int|float;

Burada önemli bir konu var: void tipi Union Type olarak kullanılamıyor çünkü herhangi bir dönüş değeri yok. Bunun dışında null tipi için iki şekilde kullanım yapabiliyorsunuz:

// Birinci yöntem
public function foo(Foo|null $foo): void;
// İkinci yöntem - ? notasyonu
public function bar(?Bar $bar): void;

Union Types ile alakalı RFC’yi incelemek isterseniz, buradan buyurabilirsiniz.

Attributes

Kendi adıma en dikkat çekici ve en merak ettiğim özelliklerin başında geliyor. Attributes, basitçe diğer dillerde Annotation diye bildiğimiz özellik aslında. PHP’de bunu ekstra bazı paketler kullanarak docblocklar içerisinde kullanabiliyorduk. Symfony framework’ü kullanmış kişiler çoğunlukla docblocklar ile olan kullanıma aşinadır. Ama artık classlara meta data eklemek için docblocklara ihtiyacımız kalmıyor. Built-in olarak Attributes bize bu imkanı sağlıyor. İnceleyecek olursak;

use App\Attributes\ExampleAttribute;#[ExampleAttribute]
class Foo
{
#[ExampleAttribute]
public const FOO = ‘foo’;

#[ExampleAttribute]
public $bar;

#[ExampleAttribute]
public function foo(#[ExampleAttribute] $bar) { }
}

Attribute classımıza bakacak olursak;

#[Attribute]
class ExampleAttribute
{
public $value;

public function __construct($value)
{
$this->value = $value;
}
}

Bu özelliğin PHP’ye ekstra bir güç katacağını ve bizlere de çok faydalı olacağını düşünüyorum. Attributes özelliği ilk olarak ortaya atıldığında PhpAttributes olarak isimlendirilmiş ama daha sonra basitleştirilerek Attributes halini almış.

Attribute kullanımı ile alakalı syntax konusunda tartışmalar ve oylamalar yapıldı. Bu süreç biraz sürdü ve şu an son karar olarak #[] syntax kullanımı şeklinde bir karar alındı. İsterseniz bu tartışmaları ve oylamaları takip edebilir, inceleyebilirsiniz.

Attributes ile alakalı çok daha detaylı bir inceleme için buraya göz atmanızı kesinlikle öneririm. RFC’yi incelemek için de buradan buyrun.

Constructor Property Promotion

Bu özellik yazmış olduğumuz classlarda, constructor içerisinde yazmış olduğumuz class propertylere data set etme durumunda fazlaca kullanabileceğimiz bir özellik. Şöyle ki;

Şu an bir class yazacak olsak ve buna bir constructor da ekleyecek olsak, şu şekilde bir şey yazabiliriz:

class Foo 
{
public Bar $bar;

public int $number;

public function __construct(Bar $bar, int $number) {
$this->bar = $bar;
$this->number = $number;
}
}

Bunu artık şöyle yazabileceğiz:

class Foo 
{
public function __construct(
public Bar $bar,
public int $number,
) {}
}

Kısa ve öz. Büyük büyük faydalar sağlayacak olmasa da, kodumuzu kısaltacağı kesin :) Constructor Promotion ile alakalı RFC’yi incelemek isterseniz, buradan buyurabilirsiniz. Ayrıca burada da detaylı bir inceleme yapılmış. Örnekleri inceleyebilirsiniz.

The nullsafe operator

Proje geliştirirken genellikle en sık yaptığımız şeylerden biri null kontrolü oluyor. PHP 7.0 ile birlikte hayatımıza giren Null coalescing operator ($foo ?? $bar) bizler için kolaylık sağlamıştı fakat metotlar ile birlikte kullanılamıyordu bu nedenle yine klasik yöntemleri kullanıyorduk. bir örnek yazalım:

$value = $class->foo();
$result = $value ? $value->bar() : null;

Yeni gelen Nullsafe operatörü ile bunu direkt olarak chain şekilde yazabileceğiz.

$result = $class->foo()?->bar();

Çok kullanışlı değil mi? Bence öyle :) Konu ile alakalı RFC’yi incelemek için buradan buyrun.

Named Arguments

En yerinde ve önemli olarak düşündüğüm özelliklerden birine geldik. Bu konuyu direkt olarak bir örnek ile izah edeceğim.

Şimdi bir metot yazdığımızı düşünelim ve bu metotun 4 adet parametresi olsun. Bu parametrelerden ilki required, kalanları optional olsun:

function foo($name, $value = null, $min = 0, $max = 10)
{
// method block
}

Artık metodumuzu kullanabiliriz. Şu an sadece name parametresini belirtip bir de sadece max parametresini değiştirmek istiyorum. Şöyle bir şey yapmam gerekiyor:

foo('PHP', null, 0, 50);

En son parametreyi değiştirmek için yine tüm parametreleri default değerleri olsa bile yazmak zorunda kaldım. Bu zor, uzun ve sıkıcı bir durum. Named Argument ile bu duruma artık gerek kalmıyor. Parametre sırası bağımsız şekilde, parametre name belirterek, istediğimiz parametrelere atama yapılmasını sağlıyoruz. Hemen örnekleyelim:

foo(max: 50, name: 'PHP');

Gördüğünüz gibi farklı sıralarda belirttim ve sadece atama yapılmasını istediklerimi yazdım. Müthiş bir esneklik kazandırıyor.

Konuyla alakalı RFC’yi buradan inceleyebilirsiniz.

Match expression

Bu özellik de bizlere fazlaca fayda sağlayacak geliştirmelerin başında geliyor. match için, switch ifadesinin daha gelişmişi, adeta bir ağabeyi diyebiliriz.

Match; bir eşleşme veya ifade döndürebilir, break ifadesine gerek duymaz, koşullar birlikte belirtilebilir ve type safe olarak kullanılır. Hemen bir örnekle inceleyecek olursak;

$value = match($param) {
0 => 'PHP',
'1', '2', '3' => 'Hello World',
8 => 'PHP 8!',
};

Burada gördüğünüz gibi bir veya birden fazla koşulu birlikte kullanıp, geriye istediğimiz bir değerin döndürülmesini sağladık. match bu işlemleri yaparken strict type kullandığı için, $param olarak verilecek girdinin, koşullarda yazılacak tipler ile tam uyuşması gerekiyor. Yani integer ise integer, string ise string. Match için 1 ile ‘1’ ifadesi farklı şeyler. Yani hem değer, hem tip karşılaştırılması yapılıyor. (===)

Ayrıca verdiğiniz parametre ile uyuşan herhangi bir koşul bulunmazsa, yani match ifadesi geri döndürecek bir şey bulamazsa, UnhandledMatchError olarak bir exception alırsınız. Bu tarz durumların önüne geçebilmek için, default bir değer döndürebilirsiniz:

$value = match($param) {
1 => 'Hello World',
default => 'no matched value',
};

Ayrıca, herhangi bir değer döndürmek yerine dilerseniz istediğiniz bir koşulda direkt olarak bir exception da fırlatabilirsiniz. (throw new Exception; )

Match ile alakalı daha detaylı bilgi için, RFC’yi buradan inceleyebilirsiniz.

JIT (Just in Time)

JIT — just in time — , programlama dillerinde runtime yöntemlerinden biri olarak geçiyor aslında. Yani PHP’ye özgü bir şey değil. Peki JIT ne yapıyor? Ne sağlıyor? Şöyle basit bir açıklama yapmaya çalışayım:

PHP’de yazmış olduğumuz kodlar PHP yorumlayıcı tarafından yorumlanıyor ve PHP motorunun anlayabileceği şekilde bytecode’a dönüştürülüyor ve burada yapılan yorumlama ile de kodunuzun çıktısı elde ediliyor. JIT tam olarak burada bize fayda sağlıyor. Her defasında tekrar tekrar PHP kodunuzun yorumlanması ve bu işlemin tekrar yapılması yerine, yorumlanmış mevcut bytecode, işlemcinin anlayacağı dile (Assembly) dönüştürülüyor. Kaynak kod içerisinde herhangi bir değişiklik olmadığı veya yeniden yorumlanmasına gerek olmadığı sürece aynı makine kodu (yorumlanıp Assembly’e dönüştürülen kod) çıktı olarak veriliyor. Burada her defasında aynı kodu yorumlamak için kullanılacak sistem kaynakları ve zamandan tasarruf edildiği için, performans ve zaman bakımınından daha iyi çıktılar elde etmemiz mümkün oluyor.

Konu ile alakalı olarak PHP’nin core geliştiricilerinden biri olan Zeev Suraski, JIT konusunu ele aldığı ve PHP7 ile PHP8 i karşılaştırdığı bir video paylaşmış.

PHP’nin JIT özelliği ile alakalı daha detaylı bilgi almak için şurada bir blog post var. RFC’yi incelemek için de buradan buyurabilirsiniz.

‘static’ Return Type

PHP 7 ile birlikte hayatımıza Function Return Type’lar girmişti. Bu zamana kadar self de dahil olmak üzere bir çok veri türünde return type kullanabiliyorduk. static hariç. PHP 8 ile birlikte static türünü de return type olarak kullanabileceğiz.

class Foo
{
public function test(): static
{
return new static();
}
}

Konu ile alakalı RFC’ye buradan ulaşabilirsiniz.

‘mixed’ Type

Docblock’lar içerisinde sıklıkla kullandığımız için, bu kavramın ne olduğuna aşinayız. Ama basitçe açıklayacak olursam; belli olmayan veya bir kaç farklı tür olabilecek değişkenler, return type’lar genellikle mixed olarak tanımlanıyor. “Karışık olsun.” der gibi. Mixed type kullanmak genel olarak çok önerilmese de, PHP’nin dinamik yapısından faydalanırken, ihtiyacımız olabiliyor. Örneğin;

  • Bir fonksiyon hiçbir şey döndürmeyebilir veya null döndürebilir.
  • Bir kaç farklı türde veri bekliyor olabiliriz.
  • PHP’nin içermediği bir tür veya türler bekliyor olabiliriz.

Yukardaki sebebler ile birlikte değerlendirilince, mixed type’ın eklenmesine faydalı diyebiliriz. mixed type şunları içeriyor:

  • array
  • bool
  • callable
  • int
  • float
  • null
  • string
  • object
  • resource

mixed type ile alakalı önemli iki husus var:

  • Mixed Type’ları sadece return type olarak değil, parametre veya class property type olarak da kullanabilirsiniz.
  • Mixed Type zaten null türünü içerdiği için, ?mixed şekilde exists notasyonu ile birlikte kullanılamaz.
// Fatal error: Mixed types cannot be nullable, 
// null is already part of the mixed type.

function bar(): ?mixed {}

Konu ile alakalı RFC’ye buradan ulaşabilirsiniz.

Throw expression

Yeni yapılan geliştirmeler ile birlikte throw u başka alanlarda da kullanabiliyoruz. Örnek olarak:

// Arrow Functions ile
$triggerError = fn () => throw new MyError();
// NullCheck notasyon ile
$foo = $bar[‘php’] ?? throw new KeyDoesNotExist(‘php’);

Konu ile alakalı RFC’ye buradan ulaşabilirsiniz.

Allowing ::class on objects

Küçük ama faydalı bir yenilik de bu. Bildiğiniz gibi classlar için ClassName::class kullanarak, classın tam ismini / kullanımı (varsa namespace ile birlikte) elde edebiliyoruz. Fakat bunu nesneler ile yapmak mümkün değildi. Ama artık mümkün. Örnek:

$foo = new Foo();
var_dump($foo::class);

Konu ile alakalı RFC’ye buradan ulaşabilirsiniz.

Non-capturing catches

Şu an PHP’de try-catch kullandığımız kod parçalarında, kullansanız da kullanmasanızda bir exception değişkeni tanımlamanız gerekiyor. Bazen amacımız sadece o exception’ı yakalamak olabiliyor ve içeriği ile (message, code vs) ilgilenmiyoruz. Bu durumlarda tanımlamış olduğumuz exception değişkeni gereksiz olarak tanımlanmış oluyor.

PHP 8 ile birlikte bu duruma el atılmış ve artık gereksiz ise, bir exception değişkeni tanımlamamıza gerek kalmıyor. Bir örnek ile inceleyelim:

// BEFORE
try {
// Something goes wrong
} catch (ExampleException $e) {
Log::error(“Something went wrong”);
}
// AFTER (in PHP 8)
try {
// Something goes wrong
} catch (ExampleException) {
Log::error(“Something went wrong”);
}

Konu ile alakalı RFC’ye buradan ulaşabilirsiniz.

Trailing comma in parameter lists

Bildiğiniz gibi array oluştururken veya function call yaparken son tanımdan sonra virgül kullanabiliyorduk. Artık function tanımlarken parameter listesinde de bunu yapabileceğiz. Örnek;

public function example(
string $param1,
int $param2,
Foo $foo,
) {
// somethings...
}

Konu ile alakalı RFC’ye buradan ulaşabilirsiniz.

Stringable Interface

string olarak tanımlanmış değişkenler ve __toString() metodu implement edilmiş classlar Stringable interface’ini taşıyacak. Eğer herhangi bir class’a __toString() magic function implementasyonu yaparsanız, otomatik olarak Stringable interface’i kullanılacak.Yani ekstra olarak class’ınıza Stringable interface’ini implements olarak göstermenize gerek yok.

class Foo
{
public function __toString(): string
{
return ‘foo’;
}
}
function bar(Stringable $stringable) { /* somethings */ }bar(new Foo());
bar(‘abc’);

Konu ile alakalı RFC’ye buradan ulaşabilirsiniz.

New str_contains() function

PHP 8 ile gelecek kullanışlı metotlardan biri. Önceden bir string içerisinde başka bir string’in bulunup bulunmadığını strpos ile kontrol ediyorduk.

if (strpos(‘we love php!’, ‘php’) !== false) {
// somethings...
}

Burada strpos metodunun davranışından ötürü bazı sorunlar yaşanabiliyordu. Bu metot eğer belirttiğiniz değeri verdiğiniz değer içerisinde bulursa, bulduğu ilk yerin indis bilgisini geri döndürüyor aksi halde false olarak dönüyor. Aradığınız değer, verilen string’in en başında olabilir ve size 0 değeri dönebilir. Bunu kesinlikle doğrulamak için === ile denklik kontrolü yaparak verileri karşılaştırmak gerekiyor. Yeni eklenen str_contains metodu ile ise bunu çok daha kolay ve doğru şekilde yapabileceğiz.

if (str_contains(‘we love php!’, ‘php’)) {
// somethings
}

Konu ile alakalı RFC’ye buradan ulaşabilirsiniz.

str_starts_with() and str_ends_with() functions

Önceden bir string’in istediğimiz bir değerle başladığını veya bittiği doğrulamak için farklı yöntemlerle kendi fonksiyonlarımızı oluşturuyorduk. PHP 8 ile birlikte bu konuyla alakalı iki yeni metot geliyor.

str_starts_with(‘hello world’, ‘hello’); // true
str_ends_with(‘hello world’, ‘world’); // true

Konu ile alakalı RFC’ye buradan ulaşabilirsiniz.

Concatenation Precedence

PHP’de string birleştirme yaparken bildiğiniz üzere . karakteri kullanıyoruz ve birden fazla string’i veya değişkeni birbirine bağlayabiliyoruz. Bazı durumlarda string birleştirme yaparken, operatör işlemleri kullanmamız gerekebiliyordu ama PHP yorumlayıcısı bunu bizim istediğimiz gibi yorumlamıyordu. Bir örnekle bakacak olursak;

echo “sum: “ . $a + $b;

Böyle bir kod yazdığımızı düşünürsek, şu an PHP bunu şu şekilde yorumlayacak:

echo (“sum: “ . $a) + $b;

PHP 8 ile birlikte bu kod şu şekilde yorumlanacak:

echo “sum: “ . ($a + $b);

Konu ile alakalı RFC’ye buradan ulaşabilirsiniz.

Bu değişiklikler dışında önemli değişiklikler ve eklemeler de mevcut. Bunları daha sonra örnekleriyle açıklayıp, yazıyı güncelleyeceğim ama o zamana kadar takip edebilmeniz adına, meraklıları için bir kaç yeniliği basitçe şöyle sıralayabilirim:

  • Weak Maps
    RFC
  • Abstract methods in traits improvements
    RFC
  • New get_debug_type() function
    RFC
  • Stricter type checks for arithmetic and bitwise operators
    RFC

Daha fazla bilgi için buradaki kaynaktan faydalanabilirsiniz. Bunun dışında PHP’nin resmi sitesindeki RFC listelerini kontrol edebilirsiniz.

Sürç-ü lisan ettiysem veya yanlış/eksik bir bilgi verdiysem, bana ulaşıp düzeltmemi sağlarsanız sevinirim. Umarım faydalı bir yazı olmuştur ve daha çıkmadan kendimizi PHP’nin yeni ve daha güçlü haline hazırlamış oluruz.

Sağlıcakla ve kodla kalın!

--

--

İzni Burak Demirtaş

nam-ı diğer Buki. 👨🏻‍💻 Sr. Software Engineer @Jotform — #php #golang #javascript #reactnative — Co-Founder at HaberSistemim & MemleketApp