PHP 8.0: Yeni İşlevler, Sınıflar ve JIT (4/4)
PHP 8.0 sürümü yayınlandı. Daha önce hiçbir sürümde olmayan yeni özelliklerle dolu. Bunların tanıtımı dört ayrı makaleyi hak ediyordu. Son bölümde yeni fonksiyonlara ve sınıflara bir göz atacağız ve Tam Zamanında Derleyici'yi tanıtacağız.
Yeni Fonksiyonlar
Standart PHP kütüphanesi yüzlerce fonksiyona sahiptir ve 8.0 sürümünde altı yeni fonksiyon ortaya çıkmıştır. Çok fazla görünmüyor, ancak bunların çoğu dilin zayıf noktalarına çare oluyor. Bu da PHP'yi daha önce hiçbir sürümde olmadığı kadar sıkılaştıran ve birleştiren 8.0 sürümünün konseptiyle güzel bir şekilde örtüşüyor. Tüm yeni işlev ve yöntemlere genel bakış geçiş kılavuzunda bulunabilir.
str_contains()
str_starts_with()
str_ends_with()
Bir dizenin başlayıp başlamadığını, bitip bitmediğini veya bir alt dize içerip içermediğini belirleyen işlevler.
if (str_contains('Nette', 'te')) {
...
}
Bu üçlünün ortaya çıkmasıyla PHP, arama sırasında boş bir dizenin nasıl ele alınacağını tanımlar, bu da diğer tüm ilgili işlevlerin bağlı olduğu şeydir ve boş bir dize her yerde bulunur:
str_contains('Nette', '') // true
str_starts_with('Nette', '') // true
strpos('Nette', '') // 0 (previously false)
Bu sayede, üçlünün davranışı Nette analoglarıyla 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şimin yükünü taşır;
tutarsızlıklar ve yanlış adımlardan kaçınılamaz. Ancak bu aynı zamanda
ilgili dilin de bir kanıtıdır. Şaşırtıcı bir şekilde, 25 yıllık PHP,
bir dizinin ilk ya da son elemanını döndürmek, kötü sürprizler olmadan
HTML'den kaçmak (htmlspecialchars
kesme işaretinden kaçmaz) ya
da sadece bir dize içinde bir dize aramak gibi temel işlemler için
işlevlerden yoksundur. Sonuç okunaklı ve anlaşılabilir bir kod olmadığı
için bir şekilde atlanabileceği anlamına gelmez. Bu, tüm API
yazarları için bir derstir. Fonksiyonun dokümantasyonunun büyük bir
kısmının tuzaklarla ilgili açıklamalardan oluştuğunu gördüğünüzde (
strpos
'un geri dönüş değerleri gibi), bu kütüphaneyi
değiştirmek ve str_contains
'u eklemek için açık bir
işarettir.
get_debug_type()
Artık kullanılmayan get_type()
adresinin yerini alır.
integer
gibi uzun türler yerine, günümüzde kullanılan
int
türünü döndürür, nesneler söz konusu olduğunda
doğrudan türü 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) |
Kaynaktan Nesneye Geçiş
Kaynak türü değerleri, PHP'nin henüz nesnelere sahip olmadığı, ancak onlara gerçekten ihtiyaç duyduğu bir zamandan gelir. Kaynaklar bu şekilde doğdu. Bugün nesnelerimiz var ve kaynaklara kıyasla çöp toplayıcı ile çok daha iyi çalışıyorlar, bu yüzden plan yavaş yavaş hepsini nesnelerle değiştirmektir.
PHP 8.0'dan itibaren resimler, curl birleşimleri, openssl, xml, vb. kaynaklar nesnelere dönüştürülmüştür. PHP 8.1'de bunu FTP bağlantıları vb. takip edecektir.
$res = imagecreatefromjpeg('image.jpg');
$res instanceof GdImage // true
is_resource($res) // false - BC break
Bu nesnelerin henüz herhangi bir yöntemi yoktur ve bunları doğrudan
örnekleyemezsiniz. Şimdiye kadar, API'yi değiştirmeden PHP'den eski
kaynaklardan kurtulma meselesi gerçekten. Ve bu iyi bir şey, çünkü iyi bir
API oluşturmak ayrı ve zorlu bir görevdir. Kimse SplFileObject gibi yeni PHP
sınıflarının fgetc()
veya fgets()
adlı
yöntemlerle oluşturulmasını istemez.
PhpToken
Tokenizer ve token_get_all
etrafındaki fonksiyonlar da
nesnelere taşınmıştır. Bu kez mesele kaynaklardan kurtulmak değil, bir PHP
belirtecini temsil eden tam teşekküllü bir nesne elde etmektir.
<?php
$tokens = PhpToken::tokenize('<?php $a = 10;');
$token = $tokens[0]; // instance PhpToken
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()
yöntemi T_WHITESPACE
,
T_COMMENT
, T_DOC_COMMENT
ve T_OPEN_TAG
belirteçleri için true değerini döndürür.
Zayıf Haritalar
Zayıf eşlemeler, artık kullanılmayan tüm nesneleri ve değerleri bellekten silen çöp toplayıcı ile ilgilidir (yani, bunları içeren bir değişken veya özellik yoktur). PHP iş parçacıkları kısa ömürlü olduğundan ve sunucularımızda bol miktarda bellek bulunduğundan, genellikle etkin bellek boşaltma ile ilgili sorunlara hiç değinmeyiz. Ancak daha uzun süre çalışan betikler için bunlar çok önemlidir.
WeakMap
nesnesi SplObjectStorage
nesnesine benzer.
Her ikisi de nesneleri anahtar olarak kullanır ve bunların altında rastgele
değerlerin saklanmasına izin verir. Aralarındaki fark, WeakMap
nesnenin çöp toplayıcı tarafından serbest bırakılmasını
engellememesidir. Yani, nesnenin şu anda bulunduğu tek yer zayıf haritada bir
anahtar ise, 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
Ne işe yarar? Örneğin, önbellekleme için. Bir blog makalesi ilettiğimiz
ve tüm yorumlarını döndüren bir loadComments()
metodumuz
olsun. Yöntem aynı makale için tekrar tekrar çağrıldığından, ilk
yöntemin sonucunu önbelleğe alacak başka bir getComments()
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]
}
...
}
Mesele şu ki, $article
nesnesi serbest bırakıldığında
(örneğin, uygulama başka bir makale ile çalışmaya başladığında),
girişi de önbellekten serbest bırakılır.
PHP JIT (Tam Zamanında Derleyici)
PHP'nin örneğin burada görebileceğiniz ve bir PHP sanal makinesi tarafından çalıştırılan düşük seviyeli talimatlar olan opcode olarak adlandırılan kodlarla derlendiğini biliyor olabilirsiniz. Peki JIT nedir? JIT, PHP'yi doğrudan işlemci tarafından çalıştırılan makine koduna şeffaf bir şekilde derleyebilir, böylece sanal makine tarafından daha yavaş yürütme atlanır.
JIT bu nedenle PHP'yi hızlandırmak için tasarlanmıştır.
JIT'i PHP'ye uygulama çabası 2011 yılına dayanmaktadır ve Dmitry Stogov tarafından desteklenmektedir. O zamandan beri 3 farklı uygulama denedi, ancak üç nedenden dolayı hiçbiri son PHP sürümüne giremedi: sonuç tipik web uygulamaları için performansta önemli bir artış olmadı; PHP bakımını zorlaştırıyor (yani Dmitry dışında kimse anlamıyor 😉); JIT kullanmak zorunda kalmadan performansı artırmanın başka yolları da vardı.
PHP sürüm 7'de gözlemlenen performans artışı, JIT üzerindeki çalışmaların bir yan ürünüydü, ancak paradoksal olarak dağıtılmamıştı. Ancak abartılı beklentilerden uzak duracağım: muhtemelen herhangi bir hızlanma görmeyeceksiniz.
Peki JIT neden PHP'ye giriyor? Öncelikle, performansı artırmanın diğer yolları yavaş yavaş tükeniyor ve JIT basitçe bir sonraki adım. Yaygın web uygulamalarında herhangi bir hız iyileştirmesi getirmez, ancak örneğin matematiksel hesaplamaları önemli ölçüde hızlandırır. Bu da bu tür şeyleri PHP'de yazmaya başlamanın yolunu açıyor. Aslında, daha önce hız nedeniyle doğrudan C uygulaması gerektiren bazı işlevleri doğrudan PHP'de uygulamak mümkün olacaktır.
JIT, opcache
uzantısının bir parçasıdır ve php.ini'de
onunla birlikte etkinleştirilir (bu dört rakamla ilgili belgeleri
okuyun):
zend_extension=php_opcache.dll
opcache.jit=1205 ; configuration using four digits OTRC
opcache.enable_cli=1 ; in order to work in the CLI as well
opcache.jit_buffer_size=128M ; dedicated memory for compiled code
JIT'in çalıştığını örneğin Tracy Bar bilgi panelinden doğrulayabilirsiniz.
JIT, tüm değişkenlerin açıkça tanımlanmış tipleri varsa ve aynı kod
tekrar tekrar çağrıldığında bile değişemiyorsa çok iyi çalışır. Bu
nedenle bir gün PHP'de de değişkenler için tür bildirip bildirmeyeceğimizi
merak
ediyorum: string $s = 'Bye, this is the end of the series';
Yorum göndermek için lütfen giriş yapın