PHP 8 naujovės ir kodėl jos svarbios

Kas pasikeitė su PHP 8 atėjimu

Kai 2020 metų lapkritį buvo išleista PHP 8 versija, daugelis programuotojų pagalvojo, kad tai bus dar vienas įprastas atnaujinimas su keliais pataisymais ir nedideliais patobulinimais. Tačiau realybė pasirodė esanti visai kitokia. PHP 8 atnešė tokių pokyčių, kurių šis programavimo kalba nematė gal net dešimtmetį. Ir ne, tai nėra dar vienas straipsnis, kuriame bus sakoma, kad „PHP mirė” ar „PHP yra atgal”. Tai apie tai, kaip viena iš populiariausių backend kalbų pagaliau sulaukė funkcionalumo, kurio programuotojai laukė metų metus.

Pirmiausia reikia pasakyti, kad PHP 8 nėra tik kosmetinis atnaujinimas. Čia kalbame apie JIT kompiliatorių, union tipus, named argumentus ir dar daugybę dalykų, kurie realiai keičia tai, kaip rašome kodą. Jei vis dar naudojate PHP 7.4 ar senesnę versiją, tikrai verta susipažinti su tuo, ką praleidžiate. O jei jau pereinate prie PHP 8.1 ar 8.2, tai šis straipsnis padės suprasti, kodėl kai kurie sprendimai buvo priimti būtent taip, o ne kitaip.

JIT kompiliatorius – ne tik greitis

Vienas didžiausių PHP 8 pasikeitimų yra JIT (Just-In-Time) kompiliatoriaus įdiegimas. Daugelis iš karto pagalvoja: „Puiku, dabar viskas veiks greičiau!” Tačiau realybė šiek tiek sudėtingesnė. JIT kompiliatorius tikrai pagerina našumą, bet ne visose situacijose taip dramatiškai, kaip galėtumėte tikėtis.

JIT veikia taip: jis analizuoja kodą vykdymo metu ir kompiliuoja dažniausiai naudojamas kodo dalis į mašininį kodą. Tai reiškia, kad jūsų PHP kodas tam tikrose situacijose gali veikti beveik taip greitai kaip C ar C++ kodas. Skamba puikiai, tiesa? Problema ta, kad dauguma web aplikacijų didžiąją laiko dalį praleidžia ne skaičiuojant, o laukdamos duomenų bazės atsakymų, failų operacijų ar išorinių API kvietimų.

Praktiškai tai reiškia, kad jei kuriate įprastą WordPress svetainę ar e-parduotuvę, JIT kompiliatorius jums gali duoti 5-10% našumo pagerinimą, o ne 300%, kaip kai kurie benchmarkai rodo. Tačiau jei dirbate su mašininio mokymosi algoritmais, vaizdo apdorojimu ar kitomis skaičiavimų intensyviomis užduotimis PHP aplinkoje, čia JIT tikrai gali padaryti didžiulį skirtumą.

Union tipai ir null-safe operatorius

Dabar pereikime prie dalykų, kurie tikrai pakeičia kasdienį programavimą. Union tipai – tai funkcionalumas, kurio PHP bendruomenė prašė jau seniai. Anksčiau, jei funkcija galėjo grąžinti arba string, arba int, arba null, turėdavote naudoti PHPDoc komentarus ir tikėtis, kad jūsų IDE juos supras. Dabar galite tiesiog parašyti:

function getUserId(string $username): int|null {
// jūsų logika čia
}

Arba dar geriau:

function processData(string|array $input): bool|string {
if (is_array($input)) {
return implode(',', $input);
}
return strlen($input) > 0;
}

Tai gali atrodyti kaip smulkmena, bet praktikoje tai reiškia mažiau klaidų, geresnį kodo supratimą ir tai, kad jūsų IDE gali daug tiksliau padėti rašant kodą. Nebereikia spėlioti, kokio tipo duomenis funkcija grąžins – tiesiog pažiūrite į funkcijos deklaraciją ir viskas aišku.

Null-safe operatorius (?->) yra kitas dalykas, kuris išgelbsti nuo begalės if tikrinimų. Anksčiau, norėdami saugiai pasiekti objekto savybes, turėdavote rašyti kažką panašaus:

$country = null;
if ($session !== null) {
$user = $session->getUser();
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->getCountry();
}
}
}

Dabar galite tiesiog parašyti:

$country = $session?->getUser()?->getAddress()?->getCountry();

Tai ne tik trumpiau, bet ir aiškiau. Iš karto matote, kad kiekvienas žingsnis gali būti null ir kodas su tuo susidoros.

Named argumentai keičia funkcijų kvietimų logiką

Named argumentai – tai funkcionalumas, kuris iš pirmo žvilgsnio gali atrodyti kaip patogumo dalykas, bet iš tikrųjų jis keičia tai, kaip projektuojame funkcijas ir API. Anksčiau, jei turėjote funkciją su daugybe parametrų, turėdavote atsiminti jų tvarką arba perduoti null reikšmes parametrams, kurių nenorėjote nurodyti.

Štai klasikinis pavyzdys:

function createUser($name, $email, $age = null, $country = null, $newsletter = false) {
// logika
}

// Anksčiau turėdavote rašyti:
createUser('Jonas', '[email protected]', null, 'Lithuania', true);

Dabar galite:

createUser(
name: 'Jonas',
email: '[email protected]',
country: 'Lithuania',
newsletter: true
);

Matote skirtumą? Nebereikia perduoti null reikšmių parametrams, kurių nenorite nurodyti. Be to, kodas tampa daug skaitomesnis – iš karto matote, kas yra kas. Tai ypač naudinga dirbant su bibliotekų funkcijomis, kurios turi daugybę opcionių parametrų.

Bet čia yra ir pavojus. Named argumentai tampa jūsų funkcijos viešojo API dalimi. Tai reiškia, kad pakeitus parametro pavadinimą, gali sugesti kodas, kuris naudoja šią funkciją su named argumentais. Tai yra breaking change, todėl projektuojant bibliotekas reikia būti atsargiems.

Match išraiška – switch steroiduose

Switch sakinys PHP visada buvo šiek tiek keistas. Reikėjo atsiminti rašyti break, jis naudojo loose comparison (==), o ne strict (===), ir apskritai jautėsi kaip kažkas iš praeities. PHP 8 pristatė match išraišką, kuri išsprendžia visas šias problemas ir dar prideda naujų galimybių.

Štai kaip atrodė switch:

switch ($statusCode) {
case 200:
case 300:
$message = 'Success';
break;
case 400:
$message = 'Bad Request';
break;
case 500:
$message = 'Server Error';
break;
default:
$message = 'Unknown';
break;
}

O štai kaip atrodo match:

$message = match ($statusCode) {
200, 300 => 'Success',
400 => 'Bad Request',
500 => 'Server Error',
default => 'Unknown',
};

Match išraiška visada grąžina reikšmę, naudoja strict comparison, nebereikia break sakinių, ir ji yra daug kompaktiškesnė. Be to, jei neapdorosite visų galimų reikšmių ir nebus default šakos, gausite UnhandledMatchError klaidą. Tai gali atrodyti kaip trūkumas, bet iš tikrųjų tai padeda pagauti klaidas ankstyvoje stadijoje.

Attributes (anksčiau vadintos anotacijomis)

Attributes – tai viena iš tų funkcijų, kurios gali neatrodyti labai svarbios, kol nepradedi jų naudoti. Anksčiau, jei norėjote pridėti metaduomenų prie klasių, metodų ar savybių, turėdavote naudoti PHPDoc komentarus. Problema ta, kad komentarai yra tiesiog tekstas – PHP juos ignoruoja, ir jei norite juos apdoroti, reikia naudoti reflection ir regex.

Dabar galite naudoti attributes:

#[Route('/api/users', methods: ['GET', 'POST'])]
class UserController {
#[Deprecated('Use getFullName() instead')]
public function getName(): string {
return $this->name;
}

#[Cache(ttl: 3600)]
public function getUsers(): array {
// logika
}
}

Attributes yra tikros PHP kalbos konstrukcijos. Jos yra kompiliuojamos, galite jas lengvai nuskaityti naudodami reflection API, ir jos gali turėti savo logiką. Tai atveria duris visokiems įdomiems dalykams – nuo routing sistemų iki dependency injection konteinerių.

Framework’ai kaip Symfony jau aktyviai naudoja attributes. Pavyzdžiui, vietoj YAML ar XML konfigūracijos failų, dabar galite tiesiog aprašyti routes tiesiogiai controller metodų viršuje. Tai daro kodą daug skaitomesnį ir lengviau prižiūrimą.

Constructor property promotion

Štai dar viena smulkmena, kuri realiai sutaupo daug rašymo. Anksčiau, norėdami sukurti paprastą klasę su keliais properties, turėdavote rašyti daug boilerplate kodo:

class User {
private string $name;
private string $email;
private int $age;

public function __construct(string $name, string $email, int $age) {
$this->name = $name;
$this->email = $email;
$this->age = $age;
}
}

PHP 8 leidžia tai supaprastinti iki:

class User {
public function __construct(
private string $name,
private string $email,
private int $age
) {}
}

Tai tas pats kodas, tik daug trumpesnis. Constructor parametrai automatiškai tampa klasės properties. Tai ypač patogu kuriant DTO (Data Transfer Objects) ar value objects, kurių dažnai reikia projektuose.

Kai kurie žmonės sako, kad tai daro kodą mažiau skaitomą, nes properties deklaracijos yra „paslėptos” constructor’iuje. Bet praktikoje, kai pripranti prie šio sintaksės, tai tampa natūralu, ir tikrai nenori grįžti prie senojo būdo.

Kodėl visa tai svarbu jūsų projektams

Gerai, pamatėme daug naujų funkcijų, bet kodėl tai svarbu praktiškai? Pirma, šios naujovės daro PHP kodą saugesniu. Union tipai, strict typing, match išraiškos – visa tai padeda pagauti klaidas kompiliavimo ar vykdymo pradžioje, o ne tada, kai jūsų klientas bando pirkti produktą ir gauna baltą ekraną.

Antra, kodas tampa skaitomesnis. Named argumentai, constructor property promotion, null-safe operatorius – visa tai leidžia rašyti kodą, kuris aiškiai išreiškia savo intencijas. Kai grįžtate prie kodo po trijų mėnesių (ar kai kitas programuotojas jį skaito), daug lengviau suprasti, kas vyksta.

Trečia, našumas. Taip, JIT kompiliatorius ne visada duoda dramatiškų rezultatų, bet kiekvienas procentas svarbu, ypač kai jūsų aplikacija auga. Be to, PHP 8.1 ir 8.2 versijos toliau tobulina našumą įvairiose srityse.

Ketvirta, bendruomenė ir ekosistema. Visi pagrindiniai framework’ai – Symfony, Laravel, WordPress – jau palaiko PHP 8 ir aktyviai naudoja naujas funkcijas. Jei norite naudoti naujausias bibliotekų versijas ir gauti saugumo pataisymus, anksčiau ar vėliau turėsite pereiti prie PHP 8.

Praktiškai, jei pradedате naują projektą, nėra jokios priežasties nenaudoti PHP 8. Jei turite esamą projektą, migracijos procesas paprastai nėra toks sudėtingas, kaip galėtumėte manyti. Dauguma PHP 7.4 kodo veiks ir PHP 8, nors gali reikėti atnaujinti kai kurias priklausomybes.

Ką daryti toliau ir kaip pradėti

Jei šis straipsnis jus įtikino, kad PHP 8 verta dėmesio, štai keletas praktinių žingsnių, kaip pradėti. Pirma, jei dar neturite PHP 8 aplinkos, susikurkite ją. Docker konteineris su PHP 8.2 užtruks gal penkias minutes. Galite naudoti oficialų PHP image arba pasiruoštas development aplinkas kaip Laravel Sail ar DDEV.

Antra, pabandykite naujoves mažame projekte ar eksperimente. Sukurkite paprastą API ar CLI įrankį naudodami match išraiškas, union tipus ir named argumentus. Tai padės suprasti, kaip šie dalykai veikia praktikoje, be rizikos sugadinti production kodą.

Trečia, jei planuojate migruoti esamą projektą, pradėkite nuo testų paleidimo PHP 8 aplinkoje. Dauguma modernių PHP projektų naudoja PHPUnit ar panašius testing framework’us. Paleiskite testus ir pažiūrėkite, kas sugenda. Dažniausiai problemos kyla dėl deprecated funkcionalumo ar pasikeitusių tipų.

Ketvirta, naudokite įrankius kaip Rector, kurie gali automatiškai atnaujinti jūsų kodą į naujesnę PHP versiją. Rector gali automatiškai pakeisti senus array sintaksės variantus, pridėti tipus, konvertuoti switch į match ir daug daugiau. Tai sutaupo daug laiko ir padeda išvengti klaidų.

Penkta, skaitykite oficialią dokumentaciją ir migration guides. PHP dokumentacija yra tikrai gera, ir kiekvienai versijai yra detalūs migration vadovai, kurie aprašo visus breaking changes ir kaip juos išspręsti.

Ir pagaliau, nebijokite eksperimentuoti. PHP 8 naujovės gali iš pradžių atrodyti keistos, ypač jei programuojate PHP jau daugelį metų ir esate įpratę prie senojo būdo. Bet duokite sau laiko priprasti, ir greitai suprasite, kodėl šie pakeitimai buvo padaryti. Šiuolaikinis PHP yra tikrai malonus kalba, su kuria dirbti, ir PHP 8 tai tik patvirtina.

Daugiau

Apache Storm realaus laiko skaičiavimai