PHP 8.0: nove funkcije, razredi in JIT (4/4)
Izdana je bila različica PHP 8.0. Polna je novih funkcij, kot jih ni imela še nobena druga različica. Njihova predstavitev je zaslužna za štiri ločene članke. V zadnjem delu si bomo ogledali nove funkcije in razrede ter predstavili prevajalnik Just in Time.
Nove funkcije
Standardna knjižnica PHP ima več sto funkcij, v različici 8.0 pa se je pojavilo šest novih. Ne zdi se veliko, vendar večina od njih odpravlja šibke točke jezika. Kar se lepo sklada s celotnim konceptom različice 8.0, ki je poostrila in utrdila PHP kot še nobena različica doslej. Pregled vseh novih funkcij in metod je na voljo v migracijskem vodniku.
str_contains()
str_starts_with()
str_ends_with()
Funkcije za ugotavljanje, ali se niz začne, konča ali vsebuje podrezec.
if (str_contains('Nette', 'te')) {
...
}
S pojavom te trojice PHP določa, kako ravnati s praznim nizom med iskanjem, kar upoštevajo vse druge povezane funkcije, in sicer prazen niz se najde povsod:
str_contains('Nette', '') // true
str_starts_with('Nette', '') // true
strpos('Nette', '') // 0 (previously false)
Zahvaljujoč temu je obnašanje te trojice popolnoma enako obnašanju analogov Nette:
str_contains() # Nette\Utils\String::contains()
str_starts_with() # Nette\Utils\String::startsWith()
str_ends_with() # Nette\Utils\String::endsWith()
Zakaj so te funkcije tako pomembne? Standardne knjižnice vseh jezikov so
vedno obremenjene z zgodovinskim razvojem; nedoslednostim in napačnim korakom
se ni mogoče izogniti. Hkrati pa so tudi pričevanje o posameznem jeziku.
Presenetljivo je, da 25 let star PHP nima funkcij za tako osnovne operacije,
kot so vračanje prvega ali zadnjega elementa polja, pobeg HTML brez neprijetnih
presenečenj (htmlspecialchars
ne pobegne apostrofu) ali samo
iskanje niza v nizu. Ne drži, da ga je mogoče nekako zaobiti, saj
rezultat ni čitljiva in razumljiva koda. To je lekcija za vse avtorje API. Ko
vidite, da večino dokumentacije funkcije zavzemajo razlage pasti (kot so
povratne vrednosti funkcije strpos
), je to jasen znak, da je treba
spremeniti knjižnico in dodati str_contains
.
get_debug_type()
Nadomešča zdaj že zastarelo get_type()
. Namesto dolgih tipov,
kot je integer
, vrne danes uporabljenega int
,
v primeru predmetov pa neposredno vrne tip:
Value | 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) |
Migracija virov v objekte
Vrednosti vrste virov izvirajo iz časov, ko PHP še ni imel objektov, vendar jih je dejansko potreboval. Tako so se rodili viri. Danes imamo predmete, ki v primerjavi z viri veliko bolje delujejo s pobiralnikom smeti, zato jih nameravamo postopoma vse nadomestiti s predmeti.
Od različice PHP 8.0 so viri slike, curl, openssl, xml itd spremenjeni v objekte. V PHP 8.1 bodo sledile povezave FTP itd.
$res = imagecreatefromjpeg('image.jpg');
$res instanceof GdImage // true
is_resource($res) // false - BC break
Ti predmeti še nimajo metod, prav tako jih ne morete neposredno
instantizirati. Zaenkrat gre le za to, da se znebimo zastarelih virov iz PHP, ne
da bi spremenili API. In to je dobro, saj je ustvarjanje dobrega API ločena in
zahtevna naloga. Nihče si ne želi ustvarjanja novih razredov PHP, kot je
SplFileObject, z metodami z imeni fgetc()
ali
fgets()
.
PhpToken
Tudi tokenizer in funkcije okoli token_get_all
so prenesene na
predmete. Tokrat ne gre za to, da bi se znebili virov, temveč dobimo
polnopraven objekt, ki predstavlja en PHP-žeton.
<?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
Metoda isIgnorable()
vrne true za žetone
T_WHITESPACE
, T_COMMENT
, T_DOC_COMMENT
in
T_OPEN_TAG
.
Šibki zemljevidi
Šibki zemljevidi so povezani z zbiralnikom smeti, ki iz pomnilnika sprosti vse predmete in vrednosti, ki se ne uporabljajo več (tj. ne vsebuje jih nobena spremenljivka ali lastnost). Ker so niti PHP kratkotrajne in imamo v strežnikih na voljo veliko pomnilnika, se z vprašanji v zvezi z učinkovitim sproščanjem pomnilnika običajno sploh ne ukvarjamo. Vendar so za dlje časa delujoče skripte bistvenega pomena.
Objekt WeakMap
je podoben objektu SplObjectStorage
.
Oba uporabljata predmete kot ključe in omogočata shranjevanje poljubnih
vrednosti pod njimi. Razlika je v tem, da objekt WeakMap
ne
preprečuje, da bi ga zbiralnik smeti sprostil. Tj. če je edino mesto, kjer
objekt trenutno obstaja, ključ v slabi mapi, bo objekt odstranjen iz mape in
pomnilnika.
$map = new WeakMap;
$obj = new stdClass;
$map[$obj] = 'data for $obj';
dump(count($map)); // 1
unset($obj);
dump(count($map)); // 0
Za kaj je to dobro? Na primer za predpomnjenje. Imejmo metodo
loadComments()
, ki ji posredujemo blogovski članek in vrne vse
njegove komentarje. Ker se metoda večkrat pokliče za isti članek, bomo
ustvarili še eno metodo getComments()
, ki bo rezultat prve metode
poslala v predpomnilnik:
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]
}
...
}
Gre za to, da se ob sprostitvi objekta $article
(na primer
aplikacija začne delati z drugim člankom) iz predpomnilnika sprosti tudi
njegov vnos.
PHP JIT (Just in Time Compiler)
Morda veste, da je PHP sestavljen v t. i. opcode, ki so navodila nizke ravni, ki jih lahko vidite na primer tukaj in ki jih izvaja virtualni stroj PHP. In kaj je JIT? JIT lahko PHP pregledno sestavi neposredno v strojno kodo, ki jo neposredno izvaja procesor, tako da je počasnejše izvajanje s strani navideznega stroja zaobideno.
Namen JIT je torej pospešiti PHP.
Prizadevanja za implementacijo JIT v PHP segajo v leto 2011, za njimi pa stoji Dmitrij Stogov. Od takrat je preizkusil tri različne izvedbe, vendar nobena od njih ni prišla v končno izdajo PHP iz treh razlogov: rezultat nikoli ni bil znatno povečanje zmogljivosti za tipične spletne aplikacije; otežuje vzdrževanje PHP (tj. nihče razen Dmitrija je ne razume 😉); obstajali so drugi načini za izboljšanje zmogljivosti brez uporabe JIT.
Skokovito povečanje zmogljivosti, opaženo v različici PHP 7, je bil stranski produkt dela na JIT, čeprav paradoksalno ni bil uporabljen. To se dogaja šele zdaj v PHP 8. Vendar bom zadržal pretirana pričakovanja: verjetno ne boste videli nobenega povečanja hitrosti.
Zakaj torej JIT vstopa v PHP? Prvič, drugih načinov za izboljšanje zmogljivosti počasi zmanjkuje, JIT pa je preprosto naslednji korak. V običajnih spletnih aplikacijah ne prinaša nobenih izboljšav hitrosti, vendar znatno pospeši na primer matematične izračune. To odpira možnost, da te stvari začnemo pisati v jeziku PHP. Pravzaprav bi bilo mogoče nekatere funkcije, ki so prej zaradi hitrosti zahtevale neposredno implementacijo v jeziku PHP, implementirati neposredno v jeziku C.
JIT je del razširitve opcache
in je omogočen skupaj z njo
v php.ini (preberite dokumentacijo
o teh štirih številkah):
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
Da je JIT zagnan, lahko preverite na primer na informacijski plošči Tracy Bar.
JIT deluje zelo dobro, če imajo vse spremenljivke jasno določene tipe in se
ne morejo spremeniti niti ob večkratnem klicanju iste kode. Zato se sprašujem,
ali bomo nekega dne tudi v PHP za spremenljivke deklarirali
tipe: string $s = 'Bye, this is the end of the series';
Če želite oddati komentar, se prijavite