Tehnologija Vesti Vodič

Šta je novo u PHP 8.3

PHP 8.3

PHP 8.3 je lansiran 23. novembra 2023 godine. Sa novom verzijom dolazi mnogo novih funkcionalnosti i poboljšanja u odnosu na prethodnu verziju (PHP 8.2). Iako se zvanično smatra manjim ažuriranjem, neke promene u verziji 8.3 mogu direktno uticati na vaš rad sa PHP-om. Zato ćemo u ovom tekstu predstaviti neke od njih.

Tipizirane konstante klasa

Mogućnost deklarisanja tipova za svojstva klasa dostupna je kao opcija od verzije PHP 7.4. Međutim, uprkos brojnim prilagođavanjima tipizacije u PHP-u tokom godina, to se sve do sada nije odnosilo i na konstante.

Sada, konstante klasa, uključujući interfejse, trejtove (traits) i Enum konstante, mogu imati i tip u PHP 8.3, čime se smanjuje verovatnoća da će programeri odstupiti od namere izvorne deklaracije konstante.

Ovo je osnovni primer korišćenja interfejsa:// Legalno:

// Legalno:
interface ConstTest {
    // Deklarisan tip i vrednost su stringovi
    const string VERSION = "PHP 8.3";
}

// Nelegalno:
interface ConstTest {
    // Neslaganje tipa i vrednosti u ovoj početnoj deklaraciji
    const float VERSION = "PHP 8.3";
}

Prava vrednost tipiziranih konstanti klasa dolazi do izražaja prilikom rada u klasama izvedenim iz osnovnih deklaracija. Iako se child klase često mogu dodeliti novoj vrednosti konstante, PHP 8.3 može pomoći u sprečavanju slučajnog menjanja njenog tipa, što bi postalo nespojivo sa izvornom deklaracijom:

class ConstTest {
    const string VERSION = "PHP 8.2";
}

class MyConstTest extends ConstTest {

    // Legalno:
    // U redu je promeniti vrednost VERSION ovde
    const string VERSION = "PHP 8.3";

    // Nelegalno:
    // Tip se mora deklarisati ako je naveden u osnovnoj klasi
    const VERSION = "PHP 8.3";

    // Nelegalno:
    // U ovom slučaju ne možemo promeniti deklarisani tip u 
    // osnovnoj klasi, čak i ako je novi tip i njegova vrednost kompatibilni.
    const float VERSION = 8.3;
}

Važno je napomenuti da tip dodeljen konstanti klase može varirati kada „sužavate“ više tipova ili koristite inače kompatibilan tip:

class ConstTest {
    const string|float VERSION = "PHP 8.2";
}

class MyConstTest extends ConstTest {

    // Legalno:
    // Ovde je u redu suziti deklaraciju tipa na string ili float
    const string VERSION = "PHP 8.3";
    const float VERSION = 8.3;

    // Legalno:
    // Vrednost može biti int, ali je kompatibilna sa float 
    const float VERSION = 8;

    // Nelegalno:
    // Ne možemo proširiti opcije tipa ovde da uključuje int
    const string|float|int VERSION = 8;
}

Dva tipa podržana za druge osobine prilikom validacije povratnih vrednosti – void i never – nisu podržani kao tipovi konstanti klasa.

Nova funkcija json_validate()

Prilikom rada sa podacima enkodiranim u JSON formatu, korisno je znati da li je payload sintaktički ispravan pre nego što pokušate nešto s njim.

U prethodnim verzijama PHP-a, programeri su koristili funkciju json_decode() i proveravali greške dok ta funkcija pokušava da pretvori JSON podatke u asocijativne nizove ili objekte. Nova funkcija json_validate() u PHP 8.3 vrši proveru grešaka bez korišćenja svih resursa potrebnih za izgradnju tih struktura nizova ili objekata.

Dakle, u prošlosti, mogli ste validirati JSON payload nešto slično ovome:

$obj = json_decode($maybeJSON);

if (json_last_error() === JSON_ERROR_NONE) {
    // Uradi nešto sa $obj   
}

Ako nameravate da odmah nešto uradite sa $obj u gornjem primeru, to je puno resursa utrošeno samo da potvrdite ispravnost originalnog JSON payload-a. U PHP 8.3 možete uraditi nešto slično i uštedeti memoriju:

if (json_validate($maybeJSON)) {
    // Uradi nešto sa $maybeJSON     
}

Napomena: Nema mnogo smisla koristiti json_validate() i odmah pokretati podatke kroz json_decode(), koristeći resurse dekodiranja u svakom slučaju. Verovatnije je da ćete koristiti novu funkciju da validirate JSON pre nego što ga negde sačuvate ili isporučite kao odgovor na zahtev.

Duboko kloniranje read-only svojstava

Mogućnost deklarisanja pojedinačnih svojstava klase kao read-only pojavila se u PHP 8.1. PHP 8.2 je uveo mogućnost dodeljivanja tog atributa celoj klasi. Međutim, mnogi programeri su osećali ograničenja kada rade sa klasama koje sadrže takva svojstva, što je u praksi ponekad ograničavalo rad.

RFC za modifikaciju read-only ponašanja dao je dva predloga:

  1. Dozvoliti klasama koje nisu samo za čitanje da nasleđuju klase koje jesu
  2. Dozvoliti ponovno inicijalizovanje svojstava samo za čitanje prilikom kloniranja

U PHP 8.3 je usvojen drugi predlog. Novi pristup omogućava instancama klase sa read-only svojstvima da se ponovno inicijalizuju unutar __clone metode (uključujući i putem funkcija pozvanih iznutra __clone metode).

Ovaj primer koda iz RFC-a pokazuje kako to funkcioniše:

class Foo {
    public function __construct(
        public readonly DateTime $bar,
        public readonly DateTime $baz
    ) {}
 
    public function __clone() {
        // $bar će dobiti novi DateTime kada se pozove klon
        $this->bar = clone $this->bar; 

        //  I ova funkcija će biti pozvana
        $this->cloneBaz();
    }
 
    private function cloneBaz() {
       // Ovo je legalno kada se poziva iznutra __clone
        unset($this->baz); 
    }
}
 
$foo = new Foo(new DateTime(), new DateTime());
$foo2 = clone $foo;

Novi atribut #[Override]

Prilikom implementacije interfejsa u PHP-u, programeri pružaju detaljne funkcionalnosti za metode navedene u tim interfejsima. Prilikom kreiranja instance klase, programeri mogu zameniti parent metodu stvaranjem alternativne verzije sa istim imenom i kompatibilnim potpisom u potklasi.

To može da nastane problem jer programeri mogu da pomisle da implementiraju metodu interfejsa ili zamjenjuju parent metodu kada to zapravo ne rade.

PHP 8.3 uvodi #[Override] atribut kako bi pomogao programerima da jasno naznače da metoda mora imati neki nasledni odnos unutar koda.

Evo jednog jednostavnog primera:

class A {
    protected function ovrTest(): void {}
}

// Ovo će raditi zbog toga što ovrTest() 
// može biti pronađen parent klasi
class B extends A {
    #[Override]
    public function ovrTest(): void {}
}

// Ovo neće raditi zbog toga što ovrBest() 
// (verovatno zbog greške u kucanju) nije u parent-u
class C extends A {
    #[Override]
    public function ovrBest(): void {}
}

Dinamičko fetch-ovanje konstanti klasa i Enum članova

Za razliku od drugih svojstava u PHP kodu, fetch-ovanje konstanti klasa i Enum članova sa imenima promenljivih bio je malo složeniji proces. Pre PHP 8.3, to ste možda radili pomoću funkcije constant() ovako:

class MyClass {
    public const THE_CONST = 9;
}

enum MyEnum: int {
    case FirstMember = 9;
    case SecondMember = 10;
}

$constantName = 'THE_CONST';
$memberName = 'FirstMember';

echo constant('MyClass::' . $constantName);
echo constant('MyEnum::' . $memberName)->value;

Sada, koristeći iste definicije klase i Enum-a kao gore, možete postići isti rezultat sa dinamičkim fetch-ovanjem konstanti u PHP 8.3:

$constantName = 'THE_CONST';
$memberName = 'FirstMember';

echo MyClass::{$constantName};
echo MyEnum::{$memberName}->value;

Nova metoda getBytesFromString()

Da li ste ikada želeli da generišete nasumične stringove koristeći unapred odobrenu kolekciju karaktera? Sada to možete lako postići sa getBytesFromString() metodom koja je dodata Random ekstenziji u PHP 8.3.

Ova nova metoda je jednostavna: prosledite joj string karaktera kao izvor materijala i navedite koliko ih želite koristiti. Metoda će zatim izabrati bajtove iz stringa nasumično dok ne dostigne tu navedenu dužinu.

Evo jednostavnog primera:

$rando = new RandomRandomizer();
$alpha = 'ABCDEFGHJKMNPQRSTVWXYZ';

$rando->getBytesFromString($alpha, 6); //  "MBXGWL"
$rando->getBytesFromString($alpha, 6); //  "LESPMG"
$rando->getBytesFromString($alpha, 6); //  "NVHWXC"

Moguće je da tražena dužina nasumičnog izlaza ima više bajtova od ulaznog stringa:

$rando = new RandomRandomizer();
$nums = '123456';

$rando->getBytesFromString($nums, 10); //  "2526341615"

Sa ulaznim stringom jedinstvenih karaktera, svaki ima jednaku šansu da bude izabran za nasumičan rezultat. Ipak, u karaktere iz po želji možete uneti (na primer iz $weighted) tako da se na izlazu dobije random vrednost u kojoj će se određeni karakteri pojavljivati češće od drugih. Na primer:

$rando = new RandomRandomizer();
$weighted = 'AAAAA12345';

$rando->getBytesFromString($weighted, 5); //  "1AA53"
$rando->getBytesFromString($weighted, 10); //  "42A5A1AA3A"

Nove metode getFloat() i nextFloat()

Proširujući Random ekstenziju, PHP 8.3 uvodi dve nove metode za generisanje nasumičnih float vrednosti: `getFloat()` i `nextFloat()`.

Evo primera korišćenja `getFloat()` metode:

$rando = new RandomRandomizer();

// Generisanje float vrednosti između minimuma 0 i maksimuma 5
$rando->getFloat(0,5); // 2.3937446906217

Metoda `getFloat()` takođe prihvata treći parametar nakon minimuma i maksimuma. Koristeći `RandomIntervalBoundary` Enum, možete odrediti da li same vrednosti minimuma i maksimuma mogu biti vraćene funkcijom.

Pravila su sledeća:

– `IntervalBoundary::ClosedOpen`: minimum može biti vraćen, ali ne i maksimum
– `IntervalBoundary::ClosedClosed`: i minimum i maksimum mogu biti vraćeni
– `IntervalBoundary::OpenClosed`: minimum ne može biti vraćen, ali maksimum može
– `IntervalBoundary::OpenOpen`: ni minimum ni maksimum ne mogu biti vraćeni

Kada koristite `getFloat()` bez specificiranja Enuma kao trećeg parametra, podrazumevano je `IntervalBoundary::ClosedOpen`.

Primer koda koji koristi `getFloat()` za generisanje nasumičnih geografskih koordinata (latitude i longitude):

$rando = new RandomRandomizer();

printf(
    "Lat: %+.6f Long: %+.6f",
    $rando->getFloat(-90, 90, RandomIntervalBoundary::ClosedClosed),

    // -180 neće biti korišćeno 
    $rando->getFloat(-180, 180, RandomIntervalBoundary::OpenClosed),
);

Nova metoda `nextFloat()` suštinski je ista kao i korišćenje `getFloat()` za zahtevanje nasumične vrednosti koja se kreće od 0 do manje od 1.

$rando = new RandomRandomizer();

$rando->nextFloat(); // 0.3767414902847

Ostale manje promene u PHP 8.3

Osim navedenih promena, PHP 8.3 uključuje i nekoliko novih funkcija i manjih izmena. Evo nekoliko od njih:

– Nove metode za klasu `DOMElement`: `DOMElement::getAttributeNames()`, `DOMElement::insertAdjacentElement()`, `DOMElement::insertAdjacentText()`, `DOMElement::toggleAttribute()`, `DOMNode::contains()`, `DOMNode::getRootNode()`, `DOMNode::isEqualNode()`, `DOMNameSpaceNode::contains()`, i `MParentNode::replaceChildren()`.
– Nove metode za klasu `IntlCalendar`: `IntlCalendar::setDate()`, `IntlCalendar::setDateTime()`, `IntlGregorianCalendar::createFromDate()`, i `IntlGregorianCalendar::createFromDateTime()`.
– Nove LDAP funkcije: `ldap_connect_wallet()` i `ldap_exop_sync()`.
– Nova multibajtna string funkcija: `mb_str_pad()`.
– Nove POSIX funkcije: `posix_sysconf()`, `posix_pathconf()`, `posix_fpathconf()`, i `posix_eaccess()`.
– Nova metoda za klasu `ReflectionMethod`: `ReflectionMethod::createFromMethodName()`.
– Nova socket funkcija: `socket_atmark()`.
– Nove string funkcije: `str_increment()`, `str_decrement()`, i `stream_context_set_options()`.
– Nova metoda za klasu `ZipArchive`: `ZipArchive::getArchiveFlag()`.
– Nova INI postavka za postavljanje maksimalne dozvoljene veličine steka: `zend.max_allowed_stack_size`.

Zastarele funkcije u PHP 8.3

Svaki put kada se pojavi nova verzija PHP-a, neke funkcije i postavke se označavaju za eventualno uklanjanje. Kada su zastarele, ne preporučuje se njihova dalja upotreba i generisaće upozorenja u mnogim logovima kada se pojave u izvršenom kodu.

Evo lista zastarelih funkcija u PHP 8.3, sa linkovima ka dodatnim informacijama:

– Konstanta `U_MULTIPLE_DECIMAL_SEPERATORS` je zastarela u korist `U_MULTIPLE_DECIMAL_SEPARATORS`.
– Mt19937 varijanta `3MT_RAND_PHP` je zastarela.
– `ReflectionClass::getStaticProperties()` više nije null-able.
– INI postavke `assert.active`, `assert.bail`, `assert.callback`, `assert.exception`, i `assert.warning` su zastarele.
– Pozivanje `get_class()` i `get_parent_class()` bez argumenata je zastarelo.

Zaključak

PHP 8.3 donosi značajna unapređenja i dodatne funkcionalnosti koje mogu značajno olakšati rad programera. Tipizirane konstante klasa omogućavaju preciznije definisanje konstanti, čime se smanjuje mogućnost grešaka u programiranju. Nova funkcija json_validate() pojednostavljuje proces provere ispravnosti JSON payload-a bez nepotrebnog dekodiranja. Unapređenja u radu s read-only svojstvima klase pružaju veću fleksibilnost i mogućnost ponovnog inicijalizovanja unutar __clone metode.

Dodatno, dodate su nove metode i funkcije, poput getBytesFromString(), getFloat() i nextFloat(), što programerima pruža više opcija za rad sa nasumičnim podacima. Uvođenje #[Override] atributa olakšava jasnoću u implementaciji interfejsa, sprečavajući nesporazume u odnosu na nasleđivanje metoda.

Važno je napomenuti da su u PHP 8.3 takođe uklonjene neke zastarele funkcije, a programeri se podstiču da prilagode svoj kod u skladu s novim standardima. Sve ove promene čine PHP 8.3 snažnim alatom za razvoj, pružajući unapređene performanse, bolju čitljivost koda i veću sigurnost u radu s različitim tipovima podataka.

Ostavi komentar

Vaša adresa neće biti objavljena