PHP 8.0: Haberlere Genel Bakış (1/4)
PHP 8.0 sürümü şu anda yayınlanıyor. Daha önce hiçbir sürümde olmadığı kadar yeni şeylerle dolu. Tanıtımı dört ayrı makaleyi hak ediyordu. İlkinde dil seviyesinde neler getirdiğine bir göz atacağız.
PHP konusuna girmeden önce, Nette'nin mevcut sürümünün sekizinci sürüm için tamamen hazır olduğunu belirtelim. Ayrıca, bir hediye olarak, tam uyumlu bir Nette 2.4 yayınlandı, bu nedenle çerçeve açısından kullanmanızı engelleyen hiçbir şey yok.
İsimlendirilmiş argümanlar
Hemen bir bomba ile başlayalım, ki bu bomba cesurca bir oyun değiştirici olarak tanımlanabilir. Argümanlar artık fonksiyonlara ve metotlara sadece konumlarına göre değil, isimlerine göre de aktarılabiliyor. Bir metodun gerçekten çok fazla parametresi olması durumunda bu kesinlikle harika bir şey:
class Response implements IResponse
{
public function setCookie(
string $name,
string $value,
string|DateInterface|null $time,
string $path = null,
string $domain = null,
bool $secure = null,
bool $httpOnly = null,
string $sameSite = null
) {
...
}
}
İlk iki argüman pozisyonel olarak, diğerleri ise isimleriyle aktarılır: (isimler pozisyonel olanlardan sonra gelmelidir)
$response->setCookie('lang', $lang, sameSite: 'None');
// instead of the horrible
$response->setCookie('lang', $lang, null, null, null, null, null, 'None');
Bu özellik sunulmadan önce Nette'de çerez göndermek için yeni bir API
oluşturma planları vardı, çünkü setCookie()
için
argümanların sayısı gerçekten artmıştı ve konumsal gösterim kafa
karıştırıcıydı. Artık buna gerek yok, çünkü adlandırılmış
argümanlar bu durumda en uygun API'dir. IDE bunları işaret edecektir ve tip
güvenliği vardır.
Kullanımlarının gerekli olmadığı mantıksal argümanları açıklamak
için bile idealdirler, ancak düz bir true
veya false
bunu kesmez:
// before
$db = $container->getService(Database::class, true);
// now
$db = $container->getService(Database::class, need: true);
Argüman adları artık genel API'nin bir parçasıdır. Artık bunları isteğe bağlı olarak değiştirmek mümkün değil. Bu nedenle Nette bile tüm argümanların uygun bir isme sahip olup olmadığını belirleyen bir denetimden geçiyor.
Adlandırılmış bağımsız değişkenler değişkenlerle birlikte de kullanılabilir:
function variadics($a, ...$args) {
dump($args);
}
variadics(a: 1, b: 2, c: 3);
// $args will contain ['b' => 2, 'c' => 3]
$args
dizisi artık sayısal olmayan anahtarlar bile
içerebilir, bu da bir tür BC molasıdır. Aynı durum, $args
dizisindeki anahtarların artık çok daha önemli bir rol oynadığı
call_user_func_array($func, $args)
davranışı için de
geçerlidir. Aksine, func_*()
ailesinin fonksiyonları
isimlendirilmiş argümanlara karşı korumalıdır.
İsimlendirilmiş argümanlar, splat operatörünün ...
artık
ilişkisel dizileri genişletebilmesiyle yakından ilgilidir:
variadics(...['b' => 2, 'c' => 3]);
Şaşırtıcı bir şekilde şu anda dizilerin içinde çalışmıyor:
$arr = [ ...['a' => 1, 'b' => 2] ];
// Fatal error: Cannot unpack array with string keys
Adlandırılmış argümanlar ve değişkenlerin kombinasyonu, örneğin
link()
metodu için, adlandırılmış argümanların yanı sıra
konumsal argümanları da aktarabileceğimiz sabit bir sözdizimine sahip olma
seçeneği sunar:
// before
$presenter->link('Product:detail', $id, 1, 2);
$presenter->link('Product:detail', [$id, 'page' => 1]); // had to be an array
// now
$presenter->link('Product:detail', $id, page: 1);
Adlandırılmış argümanlar için sözdizimi, diziler yazmaktan çok daha
seksidir, bu nedenle Latte
bunu hemen benimsedi, örneğin {include}
ve
{link}
etiketlerinde kullanılabilir:
{include 'file.latte' arg1: 1, arg2: 2}
{link default page: 1}
Adlandırılmış argümanlara serinin üçüncü bölümünde niteliklerle bağlantılı olarak geri döneceğiz.
Bir ifade bir istisna fırlatabilir
İstisna fırlatmak artık bir ifadedir. Parantez içine alabilir ve bir
if
koşuluna ekleyebilirsiniz. Hmmm, bu kulağa pek pratik
gelmiyor. Ancak, bu çok daha ilginç:
// before
if (!isset($arr['value'])) {
throw new \InvalidArgumentException('value not set');
}
$value = $arr['value'];
// now, when throw is an expression
$value = $arr['value'] ?? throw new \InvalidArgumentException('value not set');
Ok fonksiyonları şimdiye kadar yalnızca bir ifade içerebildiğinden, bu özellik sayesinde artık istisnalar atabilirler:
// only single expression
$fn = fn() => throw new \Exception('oops');
Eşleşme İfadesi
switch-case
deyiminin iki önemli kusuru vardır:
==
yerine katı olmayan karşılaştırma kullanır.===
break
adresini yanlışlıkla unutmamak için dikkatli olmalısınız
Bu nedenle PHP, katı karşılaştırma kullanan ve tersine
break
kullanmayan yeni bir match
ifadesi biçiminde
bir alternatifle birlikte gelir.
switch
kod örneği:
switch ($statusCode) {
case 200:
case 300:
$message = $this->formatMessage('ok');
break;
case 400:
$message = $this->formatMessage('not found');
break;
case 500:
$message = $this->formatMessage('server error');
break;
default:
$message = 'unknown status code';
break;
}
Ve aynısı (sadece katı karşılaştırma ile) match
kullanılarak yazılmıştır:
$message = match ($statusCode) {
200, 300 => $this->formatMessage('ok'),
400 => $this->formatMessage('not found'),
500 => $this->formatMessage('server error'),
default => 'unknown status code',
};
match
adresinin switch
gibi bir kontrol yapısı
değil, bir ifade olduğuna dikkat edin. Örnekte, sonuç değerini bir
değişkene atıyoruz. Aynı zamanda, bireysel “seçenekler” de ifadelerdir,
bu nedenle switch
örneğinde olduğu gibi daha fazla adım yazmak
mümkün değildir.
Eşleşme olmaması durumunda (ve varsayılan cümle yoksa),
UnhandledMatchError
istisnası atılır.
Bu arada, Latte'de {switch}
, {case}
ve
{default}
etiketleri de bulunmaktadır. Bunların işlevleri yeni
match
ile tam olarak örtüşmektedir. Sıkı karşılaştırma
kullanırlar, break
gerektirmezler ve case
içinde
virgülle ayrılmış birden fazla değer belirtmek mümkündür.
Nullsafe operatörü
İsteğe bağlı zincirleme, null ile karşılaştığında değerlendirmesi
durdurulan bir ifade yazmanıza olanak tanır. Bu, yeni ?->
operatörü sayesinde gerçekleşir. Aksi takdirde tekrar tekrar null olup
olmadığını kontrol etmek zorunda kalacak birçok kodun yerini alır:
$user?->getAddress()?->street
// approximately translates to
$user !== null && $user->getAddress() !== null
? $user->getAddress()->street
: null
Neden “yaklaşık olarak”? Çünkü gerçekte ifade daha ustaca
değerlendiriliyor, böylece hiçbir adım tekrarlanmıyor. Örneğin,
$user->getAddress()
yalnızca bir kez çağrılır, bu nedenle
yöntemin ilk ve ikinci kez farklı bir şey döndürmesinden kaynaklanan
sorunla karşılaşılamaz.
Bu özellik bir yıl önce Latte tarafından getirilmişti. Şimdi PHP'nin kendisi bunu benimsiyor. Harika.
Kurucu özellik tanıtımı
Türü iki kez ve değişkeni dört kez yazmaktan kurtaran sözdizimsel şeker. Bugün bunu bizim için yazan bu kadar akıllı IDE'lere sahip olmadığımız bir zamanda gelmemiş olması üzücü 🙂
class Facade
{
private Nette\Database\Connection $db;
private Nette\Mail\Mailer $mailer;
public function __construct(Nette\Database\Connection $db, Nette\Mail\Mailer $mailer)
{
$this->db = $db;
$this->mailer = $mailer;
}
}
class Facade
{
public function __construct(
private Nette\Database\Connection $db,
private Nette\Mail\Mailer $mailer,
) {}
}
Nette DI ile çalışır, kullanmaya başlayabilirsiniz.
Aritmetik ve bitsel işleçler için daha sıkı tür denetimleri
Bir zamanlar dinamik betik dillerinin öne çıkmasına yardımcı olan şey, onların en zayıf noktası haline geldi. Bir zamanlar PHP “sihirli tırnak işaretlerinden”, global değişken kayıtlarından kurtuldu ve şimdi rahat davranışın yerini katılık alıyor. PHP'de hiçbir anlam ifade etmeyen hemen her veri türünü ekleyebildiğiniz, çarpabildiğiniz vs. zamanlar çoktan geride kaldı. Sürüm 7.0'dan başlayarak, PHP gittikçe daha katı hale geliyor ve sürüm 8.0'dan bu yana, diziler, nesneler veya kaynaklar üzerinde herhangi bir aritmetik / bitsel operatör kullanma girişimi TypeError ile sona eriyor. Bunun istisnası dizilerin eklenmesidir.
// arithmetic and bitwise operators
+, -, *, /, **, %, <<, >>, &, |, ^, ~, ++, --:
Daha sağlıklı dize-sayı karşılaştırmaları
Ya da gevşek operatörü tekrar harika hale getirin.
Görünüşe göre artık ==
gevşek operatörüne yer yok, bu
sadece ===
yazarken yapılan bir yazım hatası, ancak bu
değişiklik onu tekrar haritaya geri döndürüyor. Eğer zaten varsa,
bırakın makul davransın. Örneğin, daha önceki “mantıksız”
karşılaştırmanın bir sonucu olarak, in_array()
sizi hoş
olmayan bir şekilde trolleyebilir:
$validValues = ['foo', 'bar', 'baz'];
$value = 0;
dump(in_array($value, $validValues));
// surprisingly returned true
// since PHP 8.0 returns false
==
adresinin davranışındaki değişiklik, sayıların ve
“sayısal” dizelerin karşılaştırılmasıyla ilgilidir ve aşağıdaki
tabloda gösterilmiştir:
Karşılaştırma | Önce | PHP 8.0 |
---|---|---|
0 == "0" |
true | true |
0 == "0.0" |
true | true |
0 == "foo" |
true | false |
0 == "" |
true | false |
42 == " 42" |
true | true |
42 == "42 " |
true | true |
42 == "42foo" |
true | false |
42 == "abc42" |
false | false |
"42" == " 42" |
true | true |
"42" == "42 " |
false | true |
Şaşırtıcı bir şekilde, herhangi bir dirençle karşılaşmadan onaylanan, dilin tam merkezinde yer alan bir BC kırılmasıdır. Ve bu iyi bir şey. JavaScript bu konuda çok kıskanç olabilir.
Hata raporlama
Birçok dahili fonksiyon artık göz ardı edilmesi kolay olan uyarılar
yerine TypeError ve ValueError'ı tetikliyor. Bir dizi çekirdek uyarısı
yeniden sınıflandırıldı. Shutup operatörü @
artık
ölümcül hataları susturmuyor. Ve PDO varsayılan olarak istisnaları
fırlatır.
Nette her zaman bunları bir şekilde çözmeye çalışmıştır. Tracy shutup operatörünün davranışını değiştirdi, Database PDO davranışını değiştirdi, Utils standart fonksiyonların yerine kolay gözden kaçan uyarılar yerine istisnalar atan fonksiyonlar içeriyor vs. Nette'in DNA'sında bulunan katı yönün dilin doğal yönü haline geldiğini görmek güzel.
Negatif dizi anahtarı artışları
$arr[-5] = 'first';
$arr[] = 'second';
İkinci elementin anahtarı ne olacak? Eskiden 0
, since PHP
8 it’s -4
idi.
Sondaki virgül
Sondaki virgülün olamayacağı son yer, fonksiyon argümanlarının tanımıydı. Bu artık geçmişte kaldı:
public function __construct(
Nette\Database\Connection $db,
Nette\Mail\Mailer $mailer, // trailing comma
) {
....
}
$object::class
Sihirli sabit ::class
aynı zamanda $object::class
nesneleriyle de çalışır ve get_class()
işlevinin tamamen
yerini alır.
İstisnaları yalnızca türe göre yakalayın
Ve son olarak: catch cümlesinde istisna için bir değişken belirtmek gerekli değildir:
try {
$container->getService(Database::class);
} catch (MissingServiceException) { // no $e
$logger->log('....');
}
Sonraki bölümlerde, veri türleriyle ilgili önemli yenilikleri göreceğiz, özniteliklerin ne olduğunu göstereceğiz, PHP'de hangi yeni işlevlerin ve sınıfların ortaya çıktığını göstereceğiz ve Tam Zamanında Derleyiciyi tanıtacağız.
Yorum göndermek için lütfen giriş yapın