PHP Vývoj. Komponenta Symfony Console - Tipy a triky
Tento článek byl vytvořen s cílem ukázat vám nejužitečnější a nejpoužívanější tipy a triky o vývoji konzole Symfony.
Nová verze PHP je již za rohem. O jakých nových implementacích byste měli vědět? Podívejte se na tento článek a zjistěte to!
PHP 8.2 se chystá vydání. Možná to bude verze, díky které se upgrade na PHP 8 bude zdát lákavý pro každého. Pojďme si říct, na co se mohou vývojáři těšit s PHP 8.2 a připravit se na jeho nejnovější verzi. Nejdříve si však v rychlosti projděme všechny verze a změny, které se u PHP v průběhu let udály.
<?php
třída User {
public int $id;
public string $name;
}
?>
<?php
$faktor = 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);
// $nums = array(10, 20, 30, 40);
?>
<?php
třída A {}
class B extends A {}
třída Producer {
public function method(): A {}
}
class ChildProducer extends Producer {
public function method(): B {}
}
?>
<?php
$array['key'] ??= computeDefault();
// je zhruba ekvivalentní
if (!isset($array['key'])) {
$array['key'] = computeDefault();
}
?>
<?php
$parts = ["apple", "pear"];
$ovocí = ['banán', 'pomeranč', ...$dílů, 'meloun'];
// ["banán", "pomeranč", "jablko", "hruška", "meloun"];
?>
<?php
// Vrací pole obsahující všechny potřebné stavy objektu.
public function __serialize(): array;
// Obnoví stav objektu ze zadaného pole dat.
public function __unserialize(array $data): void;
?>
Verze PHP 8.0 vydaná v listopadu 2020 přinesla nás dosud nejlepší funkce, mezi které patří:
htmlspecialchars($string, double_encode: false);
třída PostsController
{
#[Route("/api/posts/{id}", methods: ["GET"])]
public function get($id) { /* ... */ }
}
třída Point {
veřejná funkce __construct(
public float $x = 0.0,
public float $y = 0.0,
public float $z = 0.0,
) {}
}
třída Number {
public function __construct(
private int|float $číslo
) {}
}
new Number('NaN'); // TypeError
echo match (8.0) {
'8.0' => "Ale ne!",
8.0 => "Tohle jsem očekával",
};
//> To je to, co jsem očekával
$country = $session?->user?->getAddress()?->country;
enum Status
{
case Draft;
case Published;
case Archived;
}
function acceptStatus(Status $status) {...}
třída BlogData
{
public readonly Status $status;
public function __construct(Status $status)
{
$this->status = $status;
}
}
$foo = $this->foo(...);
$fn = strlen(...);
třída Service
{
private Logger $logger;
public function __construct(
Logger $logger = new NullLogger(),
) {
$this->logger = $logger;
}
}
funkce count_and_iterate(Iterator&Countable $value) {
foreach ($value as $val) {
echo $val;
}
count($value);
}
$response = $httpClient->request('https://example.com/');
print json_decode($response->getBody()->buffer())['code'];
PHP 8.2 přináší další změny, jejichž cílem je usnadnit vývojářům život a ještě více optimalizovat jejich práci. Níže je uveden seznam nových funkcí.
Jedním z největších vylepšení v nové verzi PHP je možnost přímého vytváření pouze pro čtení třída. Třída popsaná touto funkcí ji bude automaticky propagovat pro své proměnné. Třídy DTO budou nyní vypadat přehledně a čistě!
readonly třída InvoiceDTO
{
public function __construct(
public UUID $uuid,
public Issuer $issuer,
public DateTime $issuedAt,
) {}
}
Druhou velkou změnou je odstranění dynamických proměnných ve třídách. Následující implementace vyhodí depreciaci v PHP 8.2 a ErrorException v budoucí verzi PHP.
třída MyUser
{
public string $name;
}
(...)
$myUser->name = 'Name'; // OK
$myUser->surname = 'Příjmení'; // deprecated / errorexception
Za zmínku stojí, že třídy implementující __get a __set metody a třídy přímo dědící z stdClass může bez překážek implementovat magické metody.
Zde vás také odkazuji na zajímavé vlákno na GitHubu, kde vývojáři PHP-CS diskutují o této změně a nutnosti upravit svůj oblíbený nástroj pro novou verzi jazyka.
V neposlední řadě můžete toto chování zakázat pomocí funkce Anotace.
#[AllowDynamicProperties]
třída MyUser
{
public string $name;
}
$myUser->surname = 'Příjmení'; // OK
null, Pravdaa falseAž dosud funkce, které vždy vracely hodnotu Pravda nebo false hodnota musela být popsána pomocí bool typ.
function alwaysTrue(): bool { return true; }
Od této chvíle můžeme používat Pravda a false jako jednoduché typy ve vrácených hodnotách funkcí.
function alwaysTrue(): true { return true; }
(DNF) je standardní způsob uspořádání logických výrazů. Konkrétně se jedná o strukturování logického výrazu do řady AND. Při použití na deklarace typů umožňuje standardní způsob zápisu kombinovaných typů Union a Intersection, se kterými si parser poradí.
Je to velká změna, protože nyní můžeme mít například nulovatelné typy průsečíků:
function getFullName((HasName&HasSurname)|null $user) { ... }
Nejsem velkým zastáncem používání Traitů a taková změna mi přijde čistě kosmetická, zejména proto, že neumožňuje používat hodnoty Traitů bez inicializace objektu.
trait Foo {
public const FLAG_1 = 1;
protected const FLAG_2 = 2;
private const FLAG_3 = 2;
public function doFoo(int $flags): void {
if ($flags & self::FLAG_1) {
echo 'Got flag 1';
}
if ($flags & self::FLAG_2) {
echo 'Got flag 2';
}
if ($flags & self::FLAG_3) {
echo 'Got flag 3';
}
}
}
Jedna z nejdůležitějších změn, na kterou se těším. V nejnovější verzi PHP budeme moci označovat proměnné jako SensitiveParameterValue. Proč bychom měli?
Stopy zásobníku PHP ve výjimkách jsou velmi užitečné pro ladění, umožňují však náhled hodnot parametrů. Představme si například PDO kód slouží k připojení k databázi. Ladicí stopa by vypadala následovně:
PDOException: Žádný takový soubor nebo adresář v /var/www/html/test.php:3
Stack trace:
#0 /var/www/html/test.php(3): PDO->__construct('mysql:host=loca...', 'root', 'password')
#1 {main}
Po použití funkce Anotace #[SensitiveParameter] náš stack trace již nebude zobrazovat hodnotu proměnné.
funkce test(
$foo,
#[SensitiveParameter] $bar,
$baz
) {
throw new Exception('Error');
}
test('foo', 'bar', 'baz');
/*
Fatální chyba: Nevyužitá výjimka: Chyba v souboru test.php:8
Stack trace:
#0 test.php(11): test('foo', Object(SensitiveParameterValue), 'baz')
#1 {main}
vhozeno v test.php na řádku 8
*/
Jako autor říká
, hlavní motivací pro tuto změnu je umožnit načítání vlastností name a value v místech, kde objekty enum nejsou povoleny, například klíče pole. Mohli bychom pracovat na polích tak, aby je bylo možné rozšířit tak, aby jako klíče umožňovaly enumy nebo všechny objekty, ale umožnit načítání vlastností enumů je jednodušší.
enum A: string {
case B = 'B';
const C = [self::B->hodnota => self::B];
}
Dříve statické metody fungovaly takto:
DateTime::createFromImmutable(): DateTime
DateTimeImmutable::createFromMutable(): DateTimeImmutable
Na adrese PHP 8.2 se změní na:
DateTime::createFromImmutable(): static
DateTimeImmutable::createFromMutable(): static
Jedná se o přelomovou změnu pro tvůrce knihoven a/nebo všech vlastních implementací DateTime.
To byly dvě funkce, které neplnily svůj účel, protože se pouze převáděly mezi ISO-8859-1 a UTF-8. PHP Manuál doporučuje používat mb_convert_encoding místo toho.
Citlivost na lokalizaci nejlépe popisuje autor RFC:
Před verzí PHP 8.0 se lokální jazyk PHP nastavoval z prostředí. Když uživatel instaluje Linux, zeptá se, v jakém jazyce má být. Uživatel si nemusí plně uvědomit důsledky tohoto rozhodnutí. Nejenže nastavuje jazyk uživatelského rozhraní pro vestavěné příkazy, ale také pronikavě mění způsob práce s řetězci v knihovně C. Například uživatel, který by při instalaci Linuxu zvolil "turečtinu", by zjistil, že aplikace volající toupper('i') by získaly tečkované velké I (U+0130, "İ").
V éře standardizovaných textových protokolů je přirozený jazyk menšinovou aplikací pro převod případů. Ale i kdyby uživatel chtěl konverzi velkých a malých písmen v přirozeném jazyce, s funkcí strtolower() by pravděpodobně neuspěl. Je to proto, že zpracovává řetězec po jednom bajtu a každý bajt předává knihovně C tolower(). Pokud je vstupem UTF-8, což je zdaleka nejoblíbenější moderní volba, funkce strtolower() řetězec zkomolí a na výstupu se obvykle objeví neplatné UTF-8.
PHP 8.0 přestal respektovat proměnné prostředí locale. Takže locale je vždy "C", pokud uživatel explicitně nezavolá setlocale(). To znamená, že většina zpětně nekompatibilních změn je již za námi. Všechny aplikace závislé na systémovém locale při převodu velkých a malých písmen starších 8bitových znakových sad by byly ve verzi PHP 8.0 rozbity.
To znamená, že všechny níže uvedené funkce budou provádět konverzi ASCII písmen z PHP.8.2:strtolower, strtoupper, stristr, stripos, strripos, lcfirst, ucfirst, ucwords, str_ireplace
V PHP máme mnoho způsobů, jak vkládat proměnné do řetězců:
- Přímé vkládání proměnných ("$foo")
- Závorky mimo proměnnou ("{$foo}")
- Závorky za znakem dolaru ("${foo}")
- Proměnné ("${expr}", ekvivalentní (řetězec) ${expr})
Aby nedošlo k záměně a zneužití, nebudou již fungovat:
"Hello ${world}";
Zastaralé: Používání ${} v řetězcích je zastaralé.
"Hello ${(world)}";
Zastaralé: Používání ${} (proměnné proměnné) v řetězcích je zastaralé.
To nejsou všechny změny, které PHP 8.2 nám nabídne. Bohužel jsme stále nezískali podporu pro generické typy, podle toho, co řekl Nikita, by monomorfizované generické typy přidaly příliš mnoho výkonnostní režie a reifikované generické typy vyžadují mnoho změn v celé kódové základně. Co je však patrné, je disciplína a vize tzv. produkt. Změny provedené v následujících verzích jazyka jsou stále jasnější a zájemci si všimnou, že PHP se ubírá správným směrem jak v oblasti zjednodušení syntaxe, tak v podpoře novinek. Očekávám, že již v příštím roce se dočkáme volání jako platný typ.
