Büyük merakla beklenen PHP 8, 26 Kasım 2020 günü yayınlandı. Yeni sürümle birlikte gelen değişiklikler, yenilikler ve aynı zamanda performans iyileştirmeleri mevcut. Bu yazımda PHP 8 ile birlikte nelerin değiştiğini paylaşacağım. Öncelikli olarak hayatımıza katılacak yeni özelliklerden bahsedeceğim. Sonrasında JIT (Just In Time) konusundan bahsedeceğim ve son olarak eski sürüme göre değiştirilen ve mevcut çalışan uygulamaların PHP 8’e güncellenmesinde sorun çıkarabilecek özelliklerden bahsedeceğim.
İçindekiler Tablosu
YENİ ÖZELLİKLER
PHP 8 Named arguments – İsimlendirilmiş Parametreler
İsimlendirilmiş parametreler hem kod okunabilirliğini arttıracak hemde kullanımı kolaylaştıracak güzel özelliklerden birisi. Methodları kullanırken ihtiyaç olmayan parametrelerin tanımlanmasından kurtaracak güzel bir yenilik. Artık PHP 8 ile methodları tüm parametrelerini sırasıyla yazmak sorunda kalmadan kullanabileceğiz. Methodda sadece gerekli olan parametrelerin isimlerini tanımlayarak kullanmak mümkün olabilecek.
Örneğin person
isminde bir method tanımlayalım. Bu method da $name
ve $age
parametreleri zorunlu, $surname
parametresi opsiyonel olsun.
function person (string $name, ?string $surname = null, int $age)
{
//İşlemler
}
Önceden bu methodu $surname
parametresi olmadan kullanabilmek için bu şekilde bir tanımlama yapıyorduk.
person('Tolga', null, 20);
Gördüğünüz gibi zorunlu olan $age
parametresini tanımlayabilmek için aradaki $surname
parametresi için de null
tanımlaması yapmak zorunda kaldım. Ama PHP 8 ile artık ne sıraya ne de opsiyonel parametrelere takılmanıza gerek yok. PHP 8 ile bu şekilde kullanabiliriz.
person(age: 20, name: 'Tolga');
Named arguments konusunun detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: Named Arguments sayfasını ziyaret edebilirsiniz.
PHP 8 Attributes
Attributes adıyla gelen yeni özellik, özellikle Symfony kullanıcıları tarafından Annotation olarak da bilinen bir özellik. Ekstra yüklenen paketler ile php ye kazandırılan bu özellik Built-in olarak PHP 8 tarafından destekleniyor. Meta datalar için dock-block (örn: phpDoc) gibi tanımlama yapmaya gerek kalmayacak.
Önceden annotation ile tanımlanan bir route örneği:
class PostsController
{
/**
* @Route("/api/posts/{id}", methods={"GET"})
*/
public function get($id) {
/* ... */
}
}
PHP 8 ile artık kullanım bu şekilde:
class PostsController { #[Route("/api/posts/{id}", methods: ["GET"])] public function get($id) { /* ... */ } }
Attributes konusunun detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: Attributes v2 sayfasını ziyaret edebilirsiniz.
PHP 8 Constructor Property Promotion
Bir sınıf içinde tanımlanmış property’lere yapıcı method(__construct
) içinde değer atamak isterseniz önceden uzun bir tanımlama yapmanız gerekiyordu. Önce property’i tanımlamalısınız, sonra yapıcı method da parametre tanımlamalısınız ve yapıcı method içinde parametreyi property’e atamalısınız. Sonuç olarak kodunuz aşağıdaki gibi oluyordu.
class Product
{
public Currency $currency;
public Category $category;
public int $price;
public function __construct(
Currency $currency,
Category $category,
int $price
) {
$this->currency = $currency;
$this->category = $category;
$this->price = $price;
}
}
PHP 8 ile bunu daha kısa ve kolay tanımlamak mümkün olacak.
class Product
{
public function __construct(
public Currency $currency,
public Category $category,
public int $price = 0,
) {}
}
Constructor property promotion konusunun detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: Constructor Property Promotion sayfasını ziyaret edebilirsiniz.
PHP 8 Union Types – Birleşik Tür Tanımlamaları
Yeni gelen özelliklerden en sevdiklerimden birisi union types. Daha önce yazmış olduğum bir yazımda Tür Dayatmadan bahsetmiştim. Php 7 de tip belirtirken sadece null ile birlikte başka bir tip daha kullanabiliyorduk örneği ?int
gibi. Eğer farklı tip tanımlamaları yapmak istersek bunu phpDoc ile yaptığımız tanımlamalarda belirtiyorduk. Mesala int|f
loat gibi bir tanımlayı PHP 7 de phpDoc olarak yapabilirken artık PHP 8 ile iki farklı tipi bir arada tanımlayabileceğiz.
// PHP 7
class Number {
/**
* @var int|float
*/
private $number;
/**
* @param int|float $number
*/
public function setNumber($number): void {
$this->number = $number;
}
/**
* @return int|float
*/
public function getNumber() {
return $this->number;
}
}
// PHP 8
class Number {
private int|float $number;
public function setNumber(int|float $number): void {
$this->number = $number;
}
public function getNumber(): int|float {
return $this->number;
}
}
Union Types konusunun detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: Union Types 2.0 sayfasını ziyaret edebilirsiniz.
PHP 8 Mixed Type – Yeni Tür: Mixed
PHP 7 ile hayatımıza giren Type Declaration/Tür Dayatma PHP 8 ile gelişmeye devam ediyor. Mixed türü artık hem return tipi, hem parametre tipi hemde class property’lerinde kullanılabilecek. Burada kullanım sırasında mixed
type’ın sadece array, bool, callable, int, float, null, object, resource
ya da string
türlerini temsil ettiği unutulmamalıdır.
// Parameter Type
public function foo(mixed $value) {}
// Return Type
public function bar(): mixed {}
// Property Type
class Product
{
public mixed $foo;
public int $bar;
}
Kullanım da dikkat edilmesi gereken diğer bir noktada mixed type kendi içerisinde null tipini barındırdığı için null ya da başka bir tip kabul edildiğini tanımlarken ?mixed
şeklinde bir tanım kullanırsanız FatalError
alırsınız.
//INVALID - Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.
function ornekMethod(?mixed $parameter) {}
//INVALID - Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.
function ornekMethod(): ?mixed {}
Mixed Types konusunun detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: Mixed Type v2 sayfasını ziyaret edebilirsiniz.
PHP 8 Match Expression
Match expression ilk bakışta switch-case’e benzer bir özellik. Ama switch-case yapısından daha kolay ve daha doğru sonuç dönmesi ile bizim için daha kullanışlı yeni bir özellik olarak switch-case’den ayrılıyor.
- Gelen tip için strict comparisons gerçekleştirerek (
===
) değer ve tip karşılaştırması yapar. Bu da gelen değerin doğru koşulla eşleşmesi ve bize doğru sonucu dönmesini sağlanmış oluyor. - Switch-case yapısındaki gibi break tanımı eklemeye gerek yok
switch (8.0) {
case '8.0':
$result = "String koşul ile eşleşti";
break;
case 8.0:
$result = "Integer koşul ile eşleşti";
break;
}
echo $result;
// String koşul ile eşleşti
// PHP 8
echo match (8.0) {
'8.0' => "String koşul ile eşleşti",
8.0 => "Integer koşul ile eşleşti",
};
// Integer koşul ile eşleşti
Match expression konusunun detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: Match expression v2 sayfasını ziyaret edebilirsiniz.
PHP 8 Nullsafe Operator
Nullsafe Operator yeni gelen özellikler arasında sevdiğim diğer bir özelliklerden birisi. Kod yazarken bir çok durumda null kontrolü yapmak zorunda kalıyoruz. Bu kontroller kodun hatasız çalışmasını sağlasada kod bloğunun uzamasına ve okunabilirliğini azalmasına neden olmaktaydı. Özellikle daha önce anlattığım Method Zincirleme özelliğinin kullanımı sırasında methodun birisi null return etmesi durumunda kodun hata vermesine neden oluyordu. Ama bu sorun nullsafe operator olarak gelen ?
ifadesi ile ortadan kalkıyor. Zincirleme methoddan herhangi birisi null return ederse zincirin diğer methodları çağırılmadan null return ediliyor.
$country = null;
if ($session !== null) {
$user = $session->user;
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->country;
}
}
}
// PHP 8
$country = $session?->user?->getAddress()?->country;
Nullsafe operator konusunun detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: Nullsafe operator sayfasını ziyaret edebilirsiniz.
PHP 8 Non-capturing catches – Değişken atamasına gerek olmayan hataların yakalanabilmesi
Önceden try-catch ile bir hata yakaladığımız zaman bu hatayı bir değişkene atamamız gerekiyordu. Artık değişken atamasına gerek olmadan hataları yakalayabileceğiz.
try { method(); } catch (PermissionException $ex) { echo "Yetkiniz Yok"; } // PHP 8 try { method(); } catch (PermissionException) { echo "Yetkiniz Yok"; }
Non-capturing catches konusunun detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: non-capturing catches sayfasını ziyaret edebilirsiniz.
Yeni Fonksiyonlar
str_contains()
String değer içinde belirtilen diğer string’in olup olmadığını kontrol eder ve boolean
değer return eder.
str_contains ( string $haystack , string $needle ) : bool str_contains("Tolga Çıbıkçı", "Tolga"); // true str_contains("Tolga Çıbıkçı", "PHP"); // false
str_contains fonksiyonun detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: str_contains sayfasını ziyaret edebilirsiniz.
str_starts_with()
String değerin belirtilen diğer string ile başlayıp başlamadığını kontrol eder ve boolean
değer return eder.
str_starts_with ( string $haystack , string $needle ) : bool str_starts_with("Tolga Çıbıkçı", "Tolga"); // true str_starts_with("Tolga Çıbıkçı", "PHP"); // false
str_ends_with()
String değerin belirtilen diğer string ile bitip bitmediğini kontrol eder ve boolean
değer return eder.
str_ends_with ( string $haystack , string $needle ) : bool str_ends_with("Tolga Çıbıkçı", "ÇIBIKÇI"); // true str_ends_with("Tolga Çıbıkçı", "PHP"); // false
str_starts_with() ve str_ends_with() fonksiyonun detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: Add str_starts_with() and str_ends_with() functions sayfasını ziyaret edebilirsiniz.
get_debug_type()
get_debug_type()
daha önceden kullandığımız gettype()
ile aynı işi yapıp bize değişkenin türünü döndürüyor. Ama buradaki önemli fark değişkenin türünün belli olmadığı durumlarda bizim için daha kullanışlı olması.
is_object($bar) ? get_class($bar) : gettype($bar); get_debug_type($bar);
get_debug_type hakkında detaylı açıklama ve örnek için PHP RFC: get_debug_type sayfasını ziyaret edebilirsiniz.
PHP 8 JIT (Just-In-Time) Compilation
JIT yeni bir terim değil aslında ama artık PHP’ de de var. PHP 8 Release notlarında paylaşılan bilgiye göre PHP 8 iki JIT derleme motoru sunmaya başlamış. Bu seçeneklerden öne çıkanı Tracing JIT olarak belirtilmiş. JIT, PHP kullanıcılarına daha iyi bir performans sunuyor ancak JIT’in performans olarak normal uygulamalara pek etkisi olmayacağı ve PHP 7.4 ile aynı performansa sahip olacağı açıklanmış. Performans artısının daha çok karşılaştırlamlarda olacağı ve performansın 3 kata kadar iyileştirildiği belirtilmiş. Ayrıca uzun süre işlem yapan uygulamalarda ise performansın 1,5 – 2 kat daha iyi olacağı belirtilmiş.
JIT (Just-In-Time) Compilation hakkında detaylı açıklama ve performans testi yapabileceğiniz örnek bir kod için PHP RFC: JIT sayfasını inceleyebilirsiniz.
DEĞİŞEN ÖZELLİKLER
Bu değişiklikleri ayrıca işlemek istedim çünkü mevcut sistemini PHP’nin eski sürümlerinden PHP 8 geçirmeyi düşünenlerin özellikle bu konularda dikkat etmeleri ve kodlarını güncellemeleri gerekebilir. Aksi durumlarda mevcut projenin çalışması konusunda sorunlar ortaya çıkayacaktır.
String – Interger karşılaştırmasında İyileştirme
PHP 8 sayısal bir ifadeyi karşılaştırırken sayı karşılaştırma işlemi kullanıyor tersi durumdaysa string karşılaştırması kullanıyor. Bu nedenle aşağıda belirtilen koşulun PHP 7 ve PHP 8 için sonuçları farklı olacak.
0 == 'foobar' // true
// PHP 8
0 == 'foobar' // false
Saner string to number comparisons olarak duyurulan bu özelliğin detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: Saner string to number comparisons sayfasını ziyaret edebilirsiniz.
Daha Tutarlı Hata Tipleri
Daha doğru ve durumu açıklayıcı hata tipleri için iyileştirler yapılmış. Kullanıcının tanımladığı methodlarda parametre hatalı olduğunda TypeError
hatası fırlatılıyor. Ancak Php’nin sunduğu bir çok methodda parametre yanlış olması durumunda method hata yerine null return ediyordu. PHP 8 ile dahili methodlarda bu durum giderildi.
// PHP 7 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 // PHP 8 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
Consistent type errors for internal functions olarak duyurulan bu özelliğin detaylı olarak açıklandığı ve farklı örneklerin bulunduğu PHP RFC: Consistent type errors for internal functions sayfasını ziyaret edebilirsiniz.
Aritmetik ve Bitsel Operatörler İçin Katı Tip Kontrolleri
Aritmetik ve bitsel operatörler önceden array
, resource
ve object
için uygulanabiliyordu ama artık uygulanamayacak. PHP 8 ile bu şekilde kullanım TypeError
oluşmasına neden olacak.
var_dump([] % [20]); // int(0) // PHP 8 var_dump([] % [20]); // TypeError
Stricter Type Checks For Arithmetic/Bitwise Operators olarak duyurulan bu özelliğin detaylı olarak açıklandığı PHP RFC: Stricter type checks for arithmetic/bitwise operators sayfasını ziyaret edebilirsiniz.
Kaynak ve Fazlası
- Burada anlatmış olduğum tüm özellikleri ve diğer yeni özellikleri PHP 8 Released sayfasından inceleyebilirsiniz.
Harika!