PHP 8.0: Újdonságok az adattípusokban (2/4)
A PHP 8.0-ás verziója nemrég jelent meg. Tele van új funkciókkal, mint egyetlen korábbi verzió sem. Bemutatásuk négy külön cikket érdemel. A második részben az adattípusokkal foglalkozunk.
Menjünk vissza a történelemben. A skalár típusú tippek bevezetése
jelentős áttörést jelentett a PHP 7-ben. Majdnem meg sem történt. Andreu Faulds, a zseniális megoldás szerzője,
aki a declare(strict_types=1)
-nak köszönhetően teljesen
visszafelé kompatibilis és opcionális volt, keményen elutasította a
közösség. Szerencsére Anthony
Ferrara annak idején megvédte őt és a javaslatot, kampányt indított,
és az RFC nagyon szorosan átment. Huhh. A PHP 8 legtöbb újdonsága a
legendás "Nikita Popov:https://nikic.github.io " jóvoltából
született, és mind úgy ment át a szavazáson, mint kés a vajon. A világ
jobbra változik.
A PHP 8 tökéletessé teszi a típusokat. A phpDoc annotációk nagy
többségét, mint a @param
, @return
és
@var
natív jelölés váltja fel. De ami a legfontosabb, a
típusokat a PHP motorja fogja ellenőrizni. Csak az olyan struktúrák
leírásai, mint a string[]
vagy a PHPStan összetettebb
megjegyzései maradnak meg a megjegyzésekben.
Uniós típusok
Az union típusok két vagy több olyan típus felsorolása, amelyet egy változó elfogadhat:
class Button
{
private string|object $caption;
public function setCaption(string|object $caption)
{
$this->caption = $caption;
}
}
Bizonyos union típusok már korábban is megjelentek a PHP-ban. Például a
nullázható típusok. Ilyen például a ?string
, amely
egyenértékű a string|null
union típussal. A kérdőjeles
jelölés rövidítésnek tekinthető. Természetesen a PHP 8-ban is működik,
de nem kombinálható függőleges vonalakkal. Tehát a
?string|object
helyett a string|object|null
kell
írni. Továbbá a iterable
mindig is egyenértékű volt a
array|Traversable
-vel . Meglepő lehet, hogy a float
is union típus, mivel elfogadja a int|float
-at is, de az értéket
a float
-re dobja.
A void
és a mixed
áltípusokat nem használhatja
unióban, mert annak nem lenne értelme.
A Nette készen áll az union típusokra. A Schemában a Expect::from()
elfogadja őket, és a prezenterek is elfogadják őket. Használhatod őket
például a render és action metódusokban:
public function renderDetail(int|array $id)
{
...
}
Másrészt a Nette DI-ben az automatikus kapcsolás elutasítja az union típusokat. Eddig nincs olyan felhasználási eset, ahol a konstruktornak lenne értelme elfogadni akár az egyik, akár a másik objektumot. Természetesen, ha ilyen felhasználási eset megjelenik, a konténer viselkedését ennek megfelelően lehet majd módosítani.
A getParameterType()
, getReturnType()
és
getPropertyType()
metódusok a Nette\Utils\Reflection
-ban az union típus esetén kivételt dobnak (ez a 3.1-es verzióban van így;
a korábbi 3.0-s verzióban ezek a metódusok a nullkompatibilitás
fenntartása érdekében visszatérnek).
mixed
A mixed
áltípus bármilyen értéket elfogad.
A paraméterek és tulajdonságok esetében ugyanazt a viselkedést
eredményezi, mintha nem adnánk meg semmilyen típust. Mi tehát a célja?
Megkülönböztetni, hogy mikor hiányzik csupán egy típus, és mikor
szándékosan mixed
.
A függvények és metódusok visszatérési értékei esetében a típus
meg nem adása különbözik a mixed
használatától. Ez a
void
ellentétét jelenti, mivel megköveteli, hogy a függvény
valamit visszaadjon. A hiányzó return ekkor végzetes hibát eredményez.
A gyakorlatban ritkán kell használni, mert az union típusoknak köszönhetően pontosan meg lehet adni az értéket. Ezért csak egyedi helyzetekben alkalmas:
function dump(mixed $var): mixed
{
// print variable
return $var;
}
false
A mixed
-től eltérően a false
új áltípust
kizárólag union típusokban használhatja. Ez a natív függvények
visszatérési típusának leírási igénye miatt alakult ki, amelyek
történelmileg hiba esetén false-t adnak vissza:
function strpos(string $haystack, string $needle): int|false
{
}
Ezért nincs true
típus. Nem használható sem a
false
önmagában, sem a false|null
, sem a
bool|false
.
static
A static
áltípus csak egy metódus visszatérési típusaként
használható. Ez azt mondja, hogy a metódus egy olyan típusú objektumot ad
vissza, amely azonos típusú magával az objektummal (míg a self
azt mondja, hogy azt az osztályt adja vissza, amelyben a metódus definiálva
van). Kiválóan alkalmas folyékony interfészek leírására:
class Item
{
public function setValue($val): static
{
$this->value = $val;
return $this;
}
}
class ItemChild extends Item
{
public function childMethod()
{
}
}
$child = new ItemChild;
$child->setValue(10)
->childMethod();
resource
Ez a típus nem létezik a PHP 8-ban, és a jövőben sem lesz bevezetve. Az
erőforrások egy reliktum abból az időből, amikor a PHP még nem
rendelkezett objektumokkal. Az erőforrásokat fokozatosan objektumok fogják
felváltani. Végül teljesen el fognak tűnni. A PHP 8.0 például a kép
erőforrást a GdImage
objektummal, a curl erőforrást pedig a
CurlHandle
objektummal helyettesíti.
Stringable
Ez egy olyan interfész, amelyet minden objektum automatikusan megvalósít
egy mágikus metódussal __toString()
.
class Email
{
public function __toString(): string
{
return $this->value;
}
}
function print(Stringable|string $s)
{
}
print('abc');
print(new Email);
Lehetőség van a class Email implements Stringable
kifejezett
megadására az osztály definíciójában, de ez nem szükséges.
Nette\Utils\Html
szintén tükrözi ezt az elnevezési sémát
azáltal, hogy a korábbi IHtmlString
helyett a
Nette\HtmlStringable
interfészt valósítja meg. Az ilyen típusú
objektumokat például a Latte nem szökteti.
Típus variancia, kontravariancia, kovariancia
A Liskov-féle helyettesítési elv (LSP) kimondja, hogy a kiterjesztő osztályok és az interfészek implementációi soha nem igényelhetnek többet és nem nyújthatnak kevesebbet, mint a szülői osztály. Vagyis a gyermek metódus nem igényelhet több argumentumot, és nem fogadhat el szűkebb típustartományt paraméterként, mint a szülő, és fordítva, nem adhat vissza szélesebb típustartományt. De kevesebbet is visszaadhat. Hogy miért? Mert különben az öröklés megszakadna. Egy függvény elfogadna egy adott típusú objektumot, de fogalma sem lenne arról, hogy milyen paramétereket adhat át a metódusainak, és azok milyen típusokat adnának vissza. Bármelyik gyerek megtörhetné.
Tehát az OOP-ban a gyermekosztály is:
- a típusok szélesebb körét fogadhatja el a paraméterekben (ezt nevezzük kontravariációnak).
- a típusok szűkebb körét adja vissza (kovariancia)
- és a tulajdonságok nem változtathatják meg a típust (invariánsak).
A PHP a 7.4-es verzió óta képes erre, és a PHP 8.0-ban minden újonnan bevezetett típus támogatja a kontravariánsságot és a kovarianciát is.
A mixed
esetében a gyermek a visszatérési értéket
bármilyen típusra szűkítheti, de a void
nem, mivel az nem
értéket, hanem annak hiányát reprezentálja. A gyermek szintén nem
hagyhatja el a típusdeklarációt, mivel ez szintén érték hiányát teszi
lehetővé.
class A
{
public function foo(mixed $foo): mixed
{}
}
class B extends A
{
public function foo($foo): string
{}
}
Az unió típusok a paraméterekben is bővíthetők, a visszatérési értékekben pedig szűkíthetők:
class A
{
public function foo(string|int $foo): string|int
{}
}
class B extends A
{
public function foo(string|int|float $foo): string
{}
}
Továbbá, a false
bővíthető bool
-re a
paraméterben, vagy fordítva bool
-re false
-ra a
visszatérési értékben.
A kovariancia/kontravariancia megsértése a PHP 8.0-ban végzetes hibához vezet.
*A sorozat következő részeiben bemutatjuk, hogy mik az attribútumok, milyen új függvények és osztályok jelentek meg a PHP-ben, és bemutatjuk a Just in Time Compilert.
A hozzászólás elküldéséhez kérjük, jelentkezzen be