PHP 8.0: Yeni Fonksiyonlar, Sınıflar ve JIT (4/4)
PHP 8.0 sürümü yayınlandı. Daha önceki hiçbir sürümde olmadığı kadar yeniliklerle dolu. Tanıtımları tam dört ayrı makale gerektirdi. Bu son bölümde yeni fonksiyonlara ve sınıflara bakacağız ve Just in Time Compiler'ı tanıtacağız.

Yeni Fonksiyonlar
PHP standart kütüphanesi yüzlerce fonksiyona sahiptir ve 8.0 sürümünde altı yeni fonksiyon ortaya çıktı. Az gibi görünebilir, ancak çoğu dilin zayıf noktalarını kapatıyor. Bu, PHP'yi daha önceki hiçbir sürümün yapmadığı kadar tamamlayan ve konsolide eden 8.0 sürümünün genel havasıyla güzel bir şekilde örtüşüyor. Tüm yeni fonksiyonların ve metotların bir özetini geçiş kılavuzunda bulabilirsiniz.
str_contains()
str_starts_with()
str_ends_with()
Bir karakter dizisinin bir alt dize ile başlayıp başlamadığını, bitip bitmediğini veya içerip içermediğini belirlemek için fonksiyonlar.
if (str_contains('Nette', 'te')) {
...
}
Bu üçlünün gelişiyle birlikte PHP, arama yaparken boş bir karakter dizisiyle nasıl başa çıkılacağını tanımlar; ilgili tüm diğer fonksiyonlar da buna uyar ve bu şu şekildedir: boş karakter dizisi her yerde bulunur:
str_contains('Nette', '') // true
str_starts_with('Nette', '') // true
strpos('Nette', '') // 0 (eskiden false)
Bu sayede, üçlünün davranışı Nette'deki benzerleriyle tamamen aynıdır:
str_contains() # Nette\Utils\String::contains()
str_starts_with() # Nette\Utils\String::startsWith()
str_ends_with() # Nette\Utils\String::endsWith()
Bu fonksiyonlar neden bu kadar önemli? Tüm dillerin standart
kütüphaneleri her zaman tarihsel gelişimle yüklenir ve tutarsızlıkların
ve yanlış adımların ortaya çıkmasını engellemek mümkün değildir.
Ancak aynı zamanda ilgili dilin kartvizitidir. 25 yıllık PHP'de, bir dizinin
ilk veya son öğesini döndürme, hile yapmadan HTML kaçış işlemi
(htmlspecialchars
kesme işaretini kaçırmaz) veya tam da bir
karakter dizisinde karakter dizisi arama gibi temel işlemler için
fonksiyonların eksik olması şaşırtıcıdır. Bunun bir şekilde
atlatılabileceği savunması geçerli değildir, çünkü sonuç okunabilir ve
anlaşılır bir kod olmaz. Bu, tüm API yazarları için bir derstir. Bir
fonksiyonun belgelerinin önemli bir bölümünün incelikleri (örneğin
strpos
'un dönüş değerleri gibi) açıklamaya ayrıldığını
gördüğünüzde, bu kütüphaneyi düzenlemek ve tam da
str_contains
'i eklemek için açık bir işarettir.
get_debug_type()
Artık kullanımdan kaldırılmış olan get_type()
'ın yerini
alır. integer
gibi uzun tipler yerine artık kullanılan
int
'i döndürür, nesneler durumunda doğrudan tipi
döndürür:
Değer | gettype() | get_debug_type() |
---|---|---|
'abc' |
string |
string |
[1, 2] |
array |
array |
231 |
integer |
int |
3.14 |
double |
float |
true |
boolean |
bool |
null |
NULL |
null |
new stdClass |
object |
stdClass |
new Foo\Bar |
object |
Foo\Bar |
function() {} |
object |
Closure |
new class {} |
object |
class@anonymous |
new class extends Foo {} |
object |
Foo@anonymous |
curl_init() |
resource |
resource (curl) |
curl_close($ch) |
resource (closed) |
resource (closed) |
Kaynakların Nesneleştirilmesi
Kaynak (resource) türündeki değerler, PHP'nin henüz nesnelere sahip olmadığı, ancak aslında onlara ihtiyaç duyduğu zamanlardan gelir. Böylece kaynaklar dünyaya geldi. Bugün nesnelerimiz var ve kaynaklara kıyasla çöp toplayıcı (garbage collector) ile çok daha iyi çalışıyorlar, bu yüzden plan, hepsini yavaş yavaş nesnelerle değiştirmektir.
PHP 8.0'dan itibaren resimler, curl bağlantıları, openssl, xml, vb. kaynakları nesnelere dönüşüyor. PHP 8.1'de sıra FTP bağlantılarına vb. gelecek.
$res = imagecreatefromjpeg('image.jpg');
$res instanceof GdImage // true
is_resource($res) // false - BC kırılması
Bu nesnelerin henüz hiçbir metodu yoktur ve örneklerini doğrudan
oluşturamazsınız. Şimdilik gerçekten sadece PHP'den eski kaynakları API'yi
değiştirmeden çıkarmakla ilgili. Ve bu iyi bir şey, çünkü iyi bir API
oluşturmak ayrı ve zorlu bir görevdir. Kimse PHP'de fgetc()
veya
fgets()
gibi adlandırılmış metotlara sahip SplFileObject gibi
başka sınıfların ortaya çıkmasını istemez.
PhpToken
Tokenizatör ve dolayısıyla token_get_all
etrafındaki
fonksiyonlar da nesnelere taşınıyor. Bu sefer kaynaklardan kurtulmakla ilgili
değil, tek bir PHP belirtecini temsil eden tam teşekküllü bir nesne
alıyoruz.
<?php
$tokens = PhpToken::tokenize('<?php $a = 10;');
$token = $tokens[0]; // PhpToken örneği
echo $token->id; // T_OPEN_TAG
echo $token->text; // '<?php'
echo $token->line; // 1
echo $token->getTokenName(); // 'T_OPEN_TAG'
echo $token->is(T_STRING); // false
echo $token->isIgnorable(); // true
isIgnorable()
metodu, T_WHITESPACE
,
T_COMMENT
, T_DOC_COMMENT
ve T_OPEN_TAG
belirteçleri için true döndürür.
Weak maps
Zayıf haritalar (Weak maps), artık kullanılmayan tüm nesneleri ve değerleri (yani onları içeren kullanılan bir değişken veya özellik yoktur) bellekten serbest bırakan çöp toplayıcı ile ilgilidir. PHP iş parçacığının ömrü kısa ömürlü olduğundan ve bugün sunucularda bol miktarda belleğimiz olduğundan, genellikle bellek verimli bir şekilde serbest bırakma sorunlarıyla hiç ilgilenmeyiz. Ancak daha uzun süre çalışan betikler için bunlar çok önemlidir.
WeakMap
nesnesi SplObjectStorage
'a benzer. Her
ikisinde de anahtar olarak nesneler kullanılır ve altlarında herhangi bir
değerin saklanmasına izin verirler. Fark, WeakMap
'in nesnenin
çöp toplayıcı tarafından serbest bırakılmasını engellememesidir. Yani,
nesnenin hala bulunduğu tek yer zayıf haritadaki bir anahtarsa, haritadan ve
bellekten kaldırılacaktır.
$map = new WeakMap;
$obj = new stdClass;
$map[$obj] = 'data for $obj';
dump(count($map)); // 1
unset($obj);
dump(count($map)); // 0
Bu ne işe yarar? Örneğin önbellekleme için. Blog yazısını
ilettiğimiz ve tüm yorumlarını döndüren bir loadComments()
metodumuz olduğunu varsayalım. Metot aynı makaleyle tekrar tekrar
çağrıldığı için, ilk metodun sonucunu önbelleğe alacak bir
getComments()
daha oluşturacağız:
class Comments
{
private WeakMap $cache;
public function __construct()
{
$this->cache = new WeakMap;
}
public function getComments(Article $article): ?array
{
$this->cache[$article] ??= $this->loadComments($article);
return $this->cache[$article]
}
...
}
İşin püf noktası, $article
nesnesi serbest bırakıldığı
anda (örneğin uygulama başka bir makaleyle çalışmaya başladığında),
önbellekteki girdisinin de serbest bırakılmasıdır.
PHP JIT (Just in Time Compiler)
Belki de PHP'nin, PHP sanal makinesi tarafından yürütülen ve örneğin burada inceleyebilirsiniz düşük seviyeli talimatlar olan opcode'a derlendiğini biliyorsunuzdur. Peki JIT nedir? JIT, PHP'yi şeffaf bir şekilde doğrudan işlemci tarafından yürütülen makine koduna derleyebilir, böylece sanal makinenin daha yavaş yürütülmesini atlar.
JIT'in amacı PHP'yi hızlandırmaktır.
PHP'ye JIT uygulama çabası 2011 yılına kadar uzanıyor ve arkasında Dmitry Stogov var. O zamandan beri 3 farklı uygulama denedi, ancak hiçbiri canlı PHP'ye girmedi ve bunun nedenleri şunlardı: sonuç hiçbir zaman tipik web uygulamaları için önemli bir performans artışı olmadı; PHP'nin bakımını zorlaştırıyor (yani Dmitry dışında kimse anlamıyor 😉); JIT kullanmadan performansı artırmanın başka yolları vardı.
PHP 7 sürümündeki sıçramalı performans artışı, paradoksal olarak dağıtımı gerçekleşmemiş olsa da JIT üzerindeki çalışmaların bir yan ürünüydü. Bu ancak PHP 8'de gerçekleşiyor. Ancak abartılı beklentileri hemen frenleyeceğim: muhtemelen herhangi bir hızlanma fark etmeyeceksiniz.
Öyleyse JIT neden PHP'ye giriyor? Birincisi, performansı artırmanın diğer yolları yavaş yavaş tükeniyor ve JIT basitçe sırada. Sıradan web uygulamalarında hızlanma sağlamasa da, örneğin matematiksel hesaplamaları önemli ölçüde hızlandırıyor. Bu, bu tür şeyleri PHP'de yazmaya başlama olasılığını açıyor. Ve aslında, şimdiye kadar hız nedeniyle doğrudan C'de uygulama gerektiren fonksiyonları doğrudan PHP'de uygulamak mümkün olabilirdi.
JIT, opcache
uzantısının bir parçasıdır ve php.ini'de
onunla birlikte etkinleştirilir (o dört basamaklı sayı için dokümantasyon
'u okuyun):
zend_extension=php_opcache.dll
opcache.jit=1205 ; OTRC dörtlüsü ile yapılandırma
opcache.enable_cli=1 ; CLI'da da çalışması için
opcache.jit_buffer_size=128M ; derlenmiş kod için ayrılmış bellek
JIT'in çalıştığını örneğin Tracy Bar'daki bilgi panelinden öğrenebilirsiniz.
JIT, tüm değişkenlerin açıkça tanımlanmış tiplere sahip olduğu ve
aynı kodun tekrarlanan çağrılarında değişemeyeceği durumlarda çok iyi
çalışır. Bu yüzden, bir gün PHP'de değişkenler için de tipleri bildirip
bildirmeyeceğimizi merak
ediyorum: string $s = 'Merhaba, bu serinin sonu';
Yorum göndermek için lütfen giriş yapın