Víte, co nikdy, ale opravdu NIKDY nemáte psát autorům open source
projektů? „Nemám čas“. Tahle dvě slova mají schopnost rozpustit
motivaci vývojářů rychleji než mizí baterka na iPhonu při scrollování
TikToku.
- „Nemám čas na to napsat opravu.“
- „Nemám čas připravit ukázku s chybou.“
- „Tohle by mělo být v dokumentaci, ale nemám čas to napsat.“
Vážně? VÁŽNĚ?!
Představte si, že jste na párty a někdo vám řekne: „Hej, ty tam
s tím pivem! Udělej mi sendvič. Nemám čas si ho udělat sám, jsem
příliš zaneprázdněn konzumací chipsů.“ Jak byste se cítili? Jako
obědový automat s lidskou tváří? Přesně tak se cítím já, když čtu
taková slova. Okamžitě ztrácím chuť věc řešit a mám nutkání se jít
věnovat čemukoliv jinému. Třeba pustému nicnedělání.
Víte, my open source vývojáři jsme zvláštní stvoření. Trávíme
hodiny našeho volného času tvorbou softwaru, který pak dáváme k dispozici
všem. Zadarmo. Dobrovolně. Jako kdyby Ježíšek rozdával dárky každý den
v roce a ne jen na Vánoce. Baví nás to. Ale tím vám nevzniká nárok nás
úkolovat jako nějaké digitální otroky. Takže když někdo přijde
s požadavkem na novou funkci, ale „nemá čas“ přiložit ruku k dílu,
okamžitě tím vyvolá otázku „a proč bych já ten čas měl mít?“ Jako
byste chtěli po Michelangelovi, aby vám vymaloval obývák, protože vy
„nemáte čas“ to udělat sami, šak stejně nemá co lepšího
na práci.
Za roky se mi nashromáždily desítky issues u různých projektů, ve
kterých jsem poprosil „Mohl bys připravit pull request?“ a odpovědí bylo
„Mohl, ale tento týden nemám čas.“ Kdyby ten nebožák onu větu
nenapsal, nejspíš bych věc dávno vyřešil. Takhle mi ale řekl, že pohrdá
mým časem. Takže to vyřešil sám za týden? Kdeže… 99 % věcí,
které kdy kdo slíbil, nikdy nedodal, tudíž i 99 % těchto issues jsou
navždy nevyřešené. Visí tam jako digitální pomníky lidské lenosti.
Takže, milí uživatelé, příště než napíšete „Nemám čas“,
zamyslete se. Ve skutečnosti říkáte: „Hej, ty tam! Tvůj volný čas nemá
žádnou hodnotu. Hoď všechno co děláš za hlavu a věnuj se MÉ
záležitosti!“ Zkuste místo toho:
- Najít ten čas. Věřte mi, existuje. Možná je schovaný mezi epizodami
vašeho oblíbeného seriálu nebo mezi scrollováním na sociálních
sítích.
- Nabídnout řešení. Nemusíte psát rovnou patch. Stačí ukázat, že
jste řešení problému fakt promýšleli.
- Motivovat správce open source, aby se vaším issue zabývali. Třeba tím,
že ukážete, jak bude úprava užitečná nejen pro vás, ale i pro celé
lidstvo a přilehlý vesmír.
Když narazíte na bug, budete chtít novou featuru, nebo zjistíte, že by
stálo za to něco doplnit do dokumentace, zkuste pro jednou prospět komunitě.
Protože v open source světě jsme všichni na jedné lodi. A ta loď pluje
na vlnách vzájemného respektu a spolupráce. Tak nezapomeňte občas také
zaveslovat, místo abyste jen seděli a stěžovali si, že nemáte čas na
pádlování. Vaše „nemám čas“ je absolutní způsob, jak zničit
motivaci lidí, kteří vám zdarma poskytují software. Zkuste si těch pár
minut nebo hodin najít. Vaše karma vám poděkuje.
A naopak SQL bylo GPT sedmdesátých let?
SQL, vzniklé v 70. letech minulého století, představovalo revoluční
průlom v interakci člověka s počítačem. Jeho design byl navržen tak,
aby se dotazy formulovaly a četly co nejvíce jako běžná angličtina.
Například, dotaz na jména a platy zaměstnanců v SQL může vypadat takto:
SELECT name, salary FROM employee
– jednoduché a srozumitelné,
že ano? Tím se databáze staly dostupné širší veřejnosti, nejen
počítačovým nerdům.
Ačkoli tento záměr byl chvályhodný, brzy se ukázalo, že na psaní SQL
dotazů jsou stejně potřeba experti. Navíc vzhledem k tomu, že nikdy
nevzniklo univerzální aplikační rozhraní, stalo se slovní ovládání pro
moderní programování spíše břemenem. Programátoři dnes komunikují
s databázemi psaním komplikovaných generátorů SQL příkazů, které
databáze následně zpětně dekódují.
A tady na scénu vstupuje GPT. Tyto pokročilé jazykové modely
přinášejí v éře umělé inteligence obdobnou revoluci, jakou SQL
znamenalo pro databáze ve své době. Umožňují interakci s databázemi na
úplně nové úrovni, o 50 let pokročilejší. Přestože zatím neexistuje
databáze, která by byla přímo ovládaná jazykovým modelem, můžeme si od
GPT nechat generovat SQL. A funguje to skvěle.
Jak na to? Stačí, když do ChatGPT zkopírujete strukturu vaší databáze,
tedy dump s příkazy CREATE TABLE
, a uvedete i název
databázového serveru, který používáte. Následně můžete klást otázky
přímo v češtině.
Pokud si chcete použití této techniky ještě více ulehčit, použijte
předpřipravený SQL
Wizard, kam stačí jen překopírovat strukturu databáze a můžete se
rovnou ptát bez dalších řečí.
Pojďme si to prakticky ukázat. Jako příklad použijeme dvě databázové
tabulky, které jsou provázané skrze cizí klíč. Tabulka users
bude obsahovat informace o uživatelích a tabulka orders
bude
ukládat informace o objednávkách, které uživatelé udělali. Zde jsou
definice těchto tabulek:
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100)
);
CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT,
created_at DATE,
amount DECIMAL(10, 2),
FOREIGN KEY (user_id) REFERENCES users(id)
);
Definice zkopírujte do ChatGPT a hned se můžete zcela přirozeně a
v češtině zeptat například na všechny objednávky od uživatele Jana
Nováka. Konkrétně zadám: „Napiš SQL, které vypíše všechny objednávky
uživatele Jana Nováka.“ A GPT odpoví například takto:
SELECT orders.order_id, orders.created_at, orders.amount
FROM orders
JOIN users ON orders.user_id = users.id
WHERE users.name = 'Jan Novák';
Takový SQL dotaz dokáže samozřejmě spousta programátorů napsat
rychleji, než by se přihlásili do ChatGPT 🙂 Ale zkusme maličko
složitější příklad: „Vypiš uživatele, kteří mají jen jednu
objednávku.“
SELECT users.id, users.name, users.email
FROM users
JOIN orders ON users.id = orders.user_id
GROUP BY users.id, users.name, users.email
HAVING COUNT(orders.order_id) = 1;
Nebo „Vypiš uživatele, kteří nemají žádnou objednávku.“
SELECT users.*
FROM users
LEFT JOIN orders ON users.id = orders.user_id
WHERE orders.order_id IS NULL;
Tady se ukazuje diametrální rozdíl v přístupu. Zatímco GPT říkám,
jaká data chci získat, v SQL musím popsat způsob, jak je získat. A to
vyžaduje znalosti a zkušenosti.
Díky GPT se můžete soustředit na to, co chcete získat, místo
toho, jak to získat, což je zvláště cenné pro ty, kteří nejsou
odborníky na SQL.
Na závěr si ukážeme, jak lze využít GPT k vytvoření databázových
trigerů. Například můžete napsat: „Přidej do tabulky users sloupec
order_count, který bude evidovat počet objednávek. Inicializuj ho na hodnotu
odpovídající aktuálnímu počtu objednávek každého uživatele. A vytvoř
trigger, který při vytvoření nebo smazání objednávky bude hodnotu
aktulizovat.“
GPT vygeneruje dotazy pro přidání a inicializaci sloupce
order_count
:
ALTER TABLE users ADD COLUMN order_count INT DEFAULT 0;
UPDATE users SET order_count = (SELECT COUNT(*) FROM orders WHERE orders.user_id = users.id);
a požadované triggery, které udržují jeho hodnotu aktuální:
CREATE TRIGGER update_order_count_after_insert
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
UPDATE users
SET order_count = order_count + 1
WHERE id = NEW.user_id;
END;
CREATE TRIGGER update_order_count_after_delete
AFTER DELETE ON orders
FOR EACH ROW
BEGIN
UPDATE users
SET order_count = order_count - 1
WHERE id = OLD.user_id;
END;
GPT nabízí způsob, jak efektivně a intuitivně pracovat s databázemi,
i těm, kteří nejsou odborníky na SQL. Je to revoluční nástroj, který
tentokrát opravdu zpřístupňuje pokročilé databázové operace
široké veřejnosti. Stále je však důležité mít na paměti, že každý
výstup by měl být pečlivě kontrolován, aby se zajistila správnost a
bezpečnost dat.
Pokud jste připraveni posunout své dovednosti, přijďte na školení ChatGPT.
Toto setkání vás naučí, jak z něj vytáhnout maximum pro váš osobní
i profesní život. Nezáleží na tom, zda jste začátečník nebo
pokročilý uživatel, školení bude pro vás velkým přínosem.
Vývoj softwaru často přináší dilema. Například jak
řešit situace, kdy getter nemá co vrátit. V tomto článku prozkoumáme
tři strategie pro implementaci getterů v PHP, které ovlivňují strukturu a
čitelnost kódu, a každá má své specifické výhody i nevýhody. Pojďme
se na ně podrobněji podívat.
Univerzální getter
s parametrem
Prvním a v Nette používaným řešením je vytvoření jediné getter
metody, která, pokud hodnota není dostupná, může dle potřeby vrátit buď
null
nebo vyhodit výjimku. O chování rozhoduje volitelný
parametr. Zde je příklad, jak by mohla metoda vypadat:
public function getFoo(bool $need = true): ?Foo
{
if (!$this->foo && $need) {
throw new Exception("Foo not available");
}
return $this->foo;
}
Hlavní výhodou tohoto přístupu je, že eliminuje potřebu mít několik
verzí getteru pro různé scénáře použití. Někdejší nevýhodou byla
horší srozumitelnost uživatelského kódu používajícího booleovské
parametry, ale ta padla s příchodem pojmenovaných parametrů, kdy lze psát
getFoo(need: false)
.
Dále tento přístup může způsobit komplikace v oblasti statické
analýzy, jelikož dle signatury se zdá, že getFoo()
může
vrátit null
v každé situaci. Nicméně nástroje jako PHPStan
umožňují explicitní dokumentaci chování metody pomocí speciálních
anotací, které zlepšují porozumění kódu a jeho správnou analýzu:
/** @return ($need is true ? Foo : ?Foo) */
public function getFoo(bool $need = true): ?Foo
{
}
Tato anotace jasně určuje, jaké návratové typy může metoda
getFoo()
generovat v závislosti na hodnotě parametru
$need
. Ale například PhpStorm jí nerozumí.
Dvojice metod: hasFoo()
a getFoo()
Další možností je rozdělit zodpovědnost na dvě metody:
hasFoo()
pro ověření existence hodnoty a getFoo()
pro její získání. Tento přístup zvyšuje přehlednost kódu a je
intuitivně srozumitelný.
public function hasFoo(): bool
{
return (bool) $this->foo;
}
public function getFoo(): Foo
{
return $this->foo ?? throw new Exception("Foo not available");
Hlavním problémem je redundance, zvláště v případech, kdy je kontrola
dostupnosti hodnoty sama o sobě náročným procesem. Pokud
hasFoo()
provádí složité operace k ověření, zda je hodnota
dostupná, a tato hodnota je poté opět získávána pomocí
getFoo()
, dojde k jejich opětovnému provedení. Hypoteticky
může být stav objektu nebo dat změněn mezi voláním hasFoo()
a getFoo()
, což může vést k nesrovnalostem. Z uživatelského
pohledu může být tento přístup méně pohodlný, protože nás nutí volat
dvojici metod s opakujícím se parametrem. A nemůžeme využít například
null-coalescing operátor.
Výhodou je, že některé nástroje pro statickou analýzu umožňují
definovat pravidlo, že po úspěšném volání hasFoo()
nedojde v
getFoo()
k vyhození výjimky.
Metody getFoo()
a
getFooOrNull()
Třetí strategií pro je rozdělení funkcionality na dvě metody:
getFoo()
pro vyhození výjimky, pokud hodnota neexistuje, a
getFooOrNull()
pro vrácení null
. Tento přístup
minimalizuje redundanci a zjednodušuje logiku.
public function getFoo(): Foo
{
return $this->getFooOrNull() ?? throw new Exception("Foo not available");
}
public function getFooOrNull(): ?Foo
{
return $this->foo;
}
Alternativou je dvojice getFoo()
a
getFooIfExists()
, ale v tomto případě nemusí být zcela
intuitivní pochopit, která metoda vyhazuje výjimku a která vrací
null
. O trošku výstižnější by byla dvojice
getFooOrThrow()
a getFoo()
. Další možností je
getFoo()
a tryGetFoo()
.
Každý z představených přístupů k implementaci getterů v PHP má
své místo v závislosti na specifických potřebách projektu a preferencích
vývojářského týmu. Při výběru vhodné strategie je důležité zvážit,
jaký dopad bude mít na čitelnost, údržbu a výkon aplikace. Volba by
odrážet snahu o co nejsrozumitelnější a nejefektivnější kód.
Pojďme jednou provždy rozlousknout tuhle věčnou otázku,
která rozděluje komunitu programátorů. Rozhodl jsem se ponořit do temných
vod regulárních výrazů, abych přinesl odpověď (spoiler: ano, je to
možné).
Takže, co vlastně HTML dokument obsahuje? Jde o mix textu, entit, značek,
komentářů a speciální značky doctype. Prozkoumejme nejprve každou
ingredienci zvlášť.
Entity
Základem HTML stránky je text, který tvoří obyčejné znaky a
speciální sekvence zvané HTML entity. Ty mohou být buď pojmenované, jako
je
pro nezlomitelnou mezeru, nebo číselné, a to buď
v desítkovém  
nebo šestnáctkovém
 
formátu. Regulární výraz, který zachytí HTML
entitu, by vypadal takto:
(?<entity>
&
(
[a-z][a-z0-9]+ # pojmenovaná entita
|
\#\d+ # desítkové číslo
|
\#x[0-9a-f]+ # hexadecimální číslo
)
;
)
Všechny regulární výrazy jsou zapsány v režimu extended, ignorují
velikost písmen a tečka představuje jakýkoliv znak. Tj. modifikátor
six
.
Značky
Tyto ikonické prvky dělají HTML tím čím je. Tag začíná
<
, následuje název tagu, možná sada atributů a uzavírá se
>
nebo />
. Atributy mohou mít volitelnou
hodnotu a ta může být uvozena do dvojitých, jednoduchých nebo žádných
uvozovek. Regulární výraz zachytávající atribut by vypadal takto:
(?<attribute>
\s+ # alespoň jeden bílý znak před atributem
[^\s"'<>=`/]+ # název atributu
(
\s* = \s* # rovnítko před hodnotou
(
" # hodnota uzavřená ve dvojitých uvozovkách
(
[^"] # libovolný znak kromě dvojité uvozovky
|
(?&entity) # nebo HTML entita
)*
"
|
' # hodnota uzavřená v jednoduchých uvozovkách
(
[^'] # libovolný znak kromě uvozovky
|
(?&entity) # nebo HTML entita
)*
'
|
[^\s"'<>=`]+ # hodnota bez uvozovek
)
)? # hodnota je volitelná
)
Všimněte si, že se odvolávám na pojmenovanou skupinu entity
definovanou dříve.
Elementy
Element může představovat jak samostatná značka (tzv. prázdný
element), tak značky párové. Existuje pevný výčet jmen prázdných
elementů, podle kterých je rozeznáme. Regulární výraz pro jejich
zachytávání by vypadal takto:
(?<void_element>
< # začátek značky
( # název elementu
img|hr|br|input|meta|area|embed|keygen|source|base|col
|link|param|basefont|frame|isindex|wbr|command|track
)
(?&attribute)* # volitelné atributy
\s*
/? # volitelné /
> # konec značky
)
Ostatní značky jsou tedy párové a zachytí je tento regulární výraz
(používám v něm odvolávku na skupinu content
, kterou teprve
nadefinujeme):
(?<element>
< # počáteční značka
(?<element_name>
[a-z][^\s/>]* # název elementu
)
(?&attribute)* # volitelné atributy
\s*
> # konec počáteční značky
(?&content)*
</ # koncová značka
(?P=element_name) # zopakujeme název elementu
\s*
> # konec koncové značky
)
Speciálním případem jsou elementy jako <script>
,
jejichž obsah se musí zpracovávat odlišně od ostatních elementů:
(?<special_element>
< # počáteční značka
(?<special_element_name>
script|style|textarea|title # název elementu
)
(?&attribute)* # volitelné atributy
\s*
> # konec počáteční značky
(?> # atomická skupina
.*? # nejmenší možný počet jakýchkoliv znaků
</ # koncová značka
(?P=special_element_name)
)
\s*
> # konec koncové značky
)
Líný kvantifikátor .*?
zajistí, že se výraz zastaví
u první ukončovací sekvence, a atomická skupina zajistí, že toto
zastavení bude definitivní.
Komentáře
Typický HTML komentář začíná sekvencí <!--
a končí
sekvencí -->
. Regulární výraz pro HTML komentáře může
vypadat takto:
(?<comment>
<!--
(?> # atomická skupina
.*? # nejmenší možný počet jakýchkoliv znaků
-->
)
)
Líný kvantifikátor .*?
opět zajistí, že se výraz zastaví
u první ukončovací sekvence, a atomická skupina zajistí, že toto
zastavení bude definitivní.
Doctype
Jde o historický relikt, který dnes existuje jen proto, aby přepnul
prohlížeč do tzv. standardního režimu. Obvykle vypadá jako
<!doctype html>
, ale může obsahovat i další znaky. Zde
je regulární výraz, který jej zachytí:
(?<doctype>
<!doctype
\s
[^>]* # jakékoliv znaky kromě '>'
>
)
Dejme to dohromady
Když máme hotové regulární výrazy zachytávající každou část HTML,
je čas vytvořit výraz pro celý HTML 5 dokument:
\s*
(?&doctype)? # volitelný doctype
(?<content>
(?&void_element) # prázdný element
|
(?&special_element) # speciální element
|
(?&element) # párový element
|
(?&comment) # komentář
|
(?&entity) # entita
|
[^<] # znak
)*
Všechny části můžeme spojit do jednoho komplexního regulárního
výrazu. Tohle je
on, superhrdina mezi regulárními výrazy se schopností parsovat
HTML 5.
Závěrečné poznámky
I když jsme si ukázali, že HTML 5 lze parsovat pomocí regulárních
výrazů, uvedený příklad k ničemu užitečný není. Nepomůže
vám se zpracováním HTML dokumentu. Vyláme si zuby u nevalidního dokumentu.
Bude pomalý. A tak dále. V praxi se používají spíš reguláry jako je
tento (pro hledání URL obrázků):
<img.+?src=["'](.+?)["'].*?>
Ale to je opravdu velmi nespolehlivé řešení, která vede k chybám.
Tento regexp chybně matchuje
třeba custom tagy jako například
<imgs-tag src="image.jpg">
, custom atributy jako
<img data-src="custom info">
, nebo selže, když atribut bude
obsahovat uvozovku <img src="mcdonald's.jpg">
. Proto je
doporučeno používat specializované knihovny. Ve světě PHP máme
smolíčka, protože rozšíření DOM podporuje pouze pravěké ztrouchnivělé
HTML 4. Naštěstí PHP 8.4 slibuje parser pro HTML
5.
Video od Microsoftu, které mělo být oslnivou ukázkou
možností Copilota, je spíš tragikomickou prezentací úpadku
programátorského řemesla.
Mluvím o tomto videu.
Má demonstrovat možnosti GitHub Copilota, mimo jiné jak pomocí něj napsat
regulární výraz pro vyhledávání značek <img>
s třídou hero-image
. Jenže už původní kód, který
upravují, je děravý jako švýcarský sýr, já bych se za něj styděl.
Copilot se nechá strhnout a místo opravy pokračuje ve stejném duchu.
Výsledkem je regulární výraz, který nezamýšleně matchuje i jiné
třídy, jiné značky, jiné atributy a tak dále. Ba co víc, selže, pokud je
atribut src
uveden před class
.
Píšu o tom, protože tato demonstrace fušeřiny, zejména vzhledem
k oficiální povaze videa, je zarážející. Jak je možné, že si toho
nevšiml ani jeden z prezentujících či jejich kolegů? Nebo si toho všimli
a řekli si, že o nic nejde? To by bylo ještě smutnější. Výuka
programování vyžaduje preciznost a důslednost, bez nichž se snadno mohou
propagovat nesprávné praktiky. Video mělo být oslavou programátorského
umění, ale já v něm vidím ponurou ukázku, jak se úroveň
programátorského řemesla propadá do propasti nedbalosti.
Ale ať nejsem jenom negativní: je tam hezky ukázáno, jak funguje Copilot
a v něm GPT, takže si je určitě pusťte 🙂
Chcete se ponořit do světa objektově orientovaného
programování v PHP, ale nevíte, kde začít? Mám pro vás nového
stručného průvodce OOP, který vás seznámí se všemi těmi pojmy, jako
class
, extends
, private
atd.
V průvodci se dozvíte, co je to:
- třída a objekt
- jmenné prostory
- dědičnost versus kompozice
- viditelnost
- klíčové slovo final
- statické vlastnosti, metody a konstanty
- rozhraní nebo abstraktní třída
- typová kontrola
- Fluent Interfaces
- traity
- a jak fungují výjimky
Průvodce si neklade za cíl udělat z vás mistry v psaní čistého kódu
nebo podat zcela vyčerpávající informace. Jeho cílem je vás rychle
seznámit se základními koncepty OOP v současném PHP a dát vám fakticky
správné informace. Tedy poskytnout pevný základ, na kterém můžete dále
stavět. Třeba aplikace v Nette.
Jako navazující čtení doporučuji podrobný průvodce
světem správného návrhu kódu. Ten je přínosný i pro všechny, co
PHP a objektově orientované programování ovládají.
Programování v jazyce PHP byla vždycky trošku výzva, ale naštěstí
prošlo mnohými změnami k lepšímu. Pamatujete na časy před verzí PHP 7,
kdy skoro každá chyba znamenala fatal error, což aplikaci okamžitě
ukončilo? V praxi to znamenalo, že jakákoli chyba mohla aplikaci zcela
zastavit, aniž by programátor měl možnost ji zachytit a náležitě na ni
reagovat. Nástroje jako Tracy využívaly magických triků, aby dokázaly
takové chyby vizualizovat a logovat. Naštěstí s příchodem PHP 7 se tohle
změnilo. Chyby nyní vyvolávají výjimky, jako jsou Error, TypeError a
ParseError, které lze snadno zachytávat a ošetřit.
Avšak i v moderním PHP existuje slabé místo, kdy se chová stejně jako
ve své páté verzi. Mluvím o chybách během kompilace. Ty nelze zachytit a
okamžitě vedou k ukončení aplikace. Jedná se o chyby úrovně
E_COMPILE_ERROR. PHP jich generuje na dvě stovky. Vzniká paradoxní situace,
že když v PHP načteme soubor se syntaktickou chybou, což může být třeba
chybějící středník, vyhodí zachytitelnou výjimku ParseError. Ovšem
v případě, že kód je sice syntakticky v pořádku, leč obsahuje chybu
odhalitelnou až při kompilaci (například dvě metody se stejným názvem),
vyústí to ve fatální chybu, kterou zachytit nelze.
try {
require 'cesta_k_souboru.php';
} catch (ParseError $e) {
echo "Syntaktická chyba v PHP souboru";
}
Bohužel, kompilační chyby v PHP nemůžeme ověřit interně. Existovala
funkce php_check_syntax()
, která navzdory názvu odhalovala
i kompilační chyby. Byla zavedena v PHP 5.0.0, ale záhy odstraněna ve
verzi 5.0.4 a od té doby nikdy nebyla nahrazena. Pro ověření správnosti
kódu se musíme spolehnout na linter z příkazové řádky:
php -l soubor.php
Z prostředí PHP lze ověřit kód uložený v proměnné
$code
třeba takto:
$code = '... PHP kód pro ověření ...';
$process = proc_open(
PHP_BINARY . ' -l',
[['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']],
$pipes,
null,
null,
['bypass_shell' => true],
);
fwrite($pipes[0], $code);
fclose($pipes[0]);
$error = stream_get_contents($pipes[1]);
if (proc_close($process) !== 0) {
echo 'Chyba v PHP souboru: ' . $error;
}
Nicméně režie spouštění externího PHP procesu kvůli ověření
jednoho souboru je docela velká. Ale dobrá zpráva přichází s verzí PHP
8.3, která přinese možnost ověřovat více souborů najednou:
php -l soubor1.php soubor2.php soubor3.php
Na operátor ??
se v PHP čekalo neskutečně dlouho, snad
deset let. Dnes je mi ale líto, že se nečekalo déle.
- Počkej, cože? Deset let? Tak to přeháníš, ne?
- Opravdu. Začal se řešit v roce 2004, pod názvem „ifsetor“.
A dostal se do PHP až v prosinci 2015 ve verzi 7.0. Takže téměř
12 let.
- Aha! Notyvole.
Škoda, že se nečekalo déle. Do současného PHP totiž nezapadá.
PHP počínaje verzí 7.0 udělalo neuvěřitelný posun ke striktnosti.
Klíčové okamžiky:
Operátor ??
zjednodušil otravné:
isset($necoCo[$musimNapsatDvakrat]) ? $necoCo[$musimNapsatDvakrat] : 'default value'
na pouhé:
$pisu[$jednou] ?? 'default value'
Jenže udělal to v době, kdy potřeba používat isset()
značně klesla. Dnes častěji počítáme s tím, že data, ke kterým
přistupujeme, existují. A pokud neexistují, tak se o tom sakra chceme
dozvědět.
Operátor ??
má ale vedlejší efekt a to schopnost detekovat
null. Což je taky nejčastější důvod k jeho užití:
$len = $this->length ?? 'default value'
Bohužel zároveň zatajuje chyby. Zatajuje překlepy:
// vždy vrátí 'default value', víte proč?
$len = $this->lenght ?? 'default value'
Zkrátka ??
jsme dostali přesně ve chvíli, kdy bychom naopak
nejvíc potřeboval zkrátit tohle:
$necoCo[$musimNapsatDvakrat] === null
? 'default value'
: $necoCo[$musimNapsatDvakrat]
Bylo by úžasné, kdyby PHP 9.0 mělo odvahu chování operátoru
??
upravit k trošku větší striktnosti. Udělat z „isset
operátoru“ opravdu „null coalesce operator“, jak se mimochodem oficiálně jmenuje.
S detekcí překlepů zamlčených operátorem ??
vám
pomůže PHPStan s nastavením checkDynamicProperties:
true.
Určitě už jste někdy narazili debatu „tabulátory vs. mezery“ pro
odsazování. Polemika probíhá od nepaměti a oba tábory vyzdvihují své
argumenty:
Tabulátory:
- odsazování je jejich účel
- menší soubory, protože odsazení zabírá jeden znak
- můžete si nastavit vlastní šířku odsazení (? k tomu se
vrátíme)
Mezery:
- kód bude vypadat všude stejně a konzistence je klíčová
- vyhnete se možným problémům v prostředích citlivých na
bílé znaky
Co když jde ale o víc než o osobní preference? ChaseMoskal nedávno
zveřejnil na Redditu velmi podnětný příspěvek s názvem Nikdo
nezmínil skutečný důvod, proč používat tabulátory místo mezer,
který vám otevře oči.
Stěžejní důvod, proč
používat tabulátory
Chase ve svém příspěvku popisuje zkušenost se zaváděním mezer na
svém pracovišti a negativní dopady, které to mělo na spolupracovníky se
zrakovým postižením.
Jeden z nich byl zvyklý používat šířku tabulátoru 1, aby se vyhnul
velkým odsazením při použití obřího písma. Druhý používá šířku
tabulátoru 8, protože mu nejlépe vyhovuje na ultraširokém monitoru. Pro oba
však představuje kód s mezerami vážný problém, musí je převádět na
tabulátory před čtením a zase zpátky na mezery před komitováním.
Pro nevidomé programátory, kteří používají braillské displeje,
představuje každá mezera jednu braillskou buňkou. Pokud je tedy výchozí
odsazení 4 mezery, odsazení 3. úrovně plýtvá 12 cennými braillskými
buňkami ještě před začátkem kódu. Na 40buňkovém displeji, který se
u notebooků používá nejčastěji, je to více než čtvrtina dostupných
buněk, které jsou promrhány bez jakékoliv informace.
Nám se může přizpůsobení šířky odsazení zdát jako zbytečnost,
jsou ale mezi námi programátoři, pro které je naprosto nezbytné. A to
prostě nemůžeme ignorovat.
Tím, že budeme v našich projektech používat tabulátory, dáváme jim
možnost tohoto přizpůsobení.
Nejdříve
přístupnost, pak osobní preference
Jistě, nejde přesvědčit každého, aby se přiklonil na jednu či druhou
stranu, jde-li o preference. Každý má své. A měli bychom být rádi za
možnost volby.
Zároveň však musíme dbát na to, abychom zohledňovali všechny. Abychom
respektovali odlišnosti a používali přístupné prostředky. Jakým je
například znak tabulátor.
Myslím, že Chase to vystihl dokonale, když ve svém příspěvku uvedl,
že „…neexistuje žádný protiargument, který by se jen blížil k tomu
převážit potřeby přístupnosti našich spolupracovníků“.
Accessible first
Stejně jako při navrhování webů se vžila metodika „mobile first“,
kdy se snažíme zajistit, aby každý, bez ohledu na zařízení, měl
s vaším produktem skvělou user experience – měli bychom usilovat o
„accessible first“ prostředí tím, že zajistíme, aby každý měl
stejnou možnost pracovat s kódem, ať už v zaměstnání nebo na opensource
projektu.
Pokud se tabulátory stanou výchozí volbou pro odsazování, odstraníme
jednu bariéru. Spolupráce pak bude příjemná pro každého, bez ohledu na
jeho schopnosti. Pokud budou mít všichni stejné možnosti, můžeme
maximálně využít společný potenciál ❤️
Článek vychází z Default
to tabs instead of spaces for an ‚accessible first‘ environment.
Podobně přesvědčivý post jsem si přečetl v roce 2008 a ještě ten den
změnil ve všech svých projektech mezery na tabulátory. Zůstala po tom stopa
v Gitu, ale samotný článek už zmizel v propadlišti dějin.
Knihovna Texy od verze 3.1.6 přidává podporu pro Latte
3 v podobě značky {texy}
. Co umí a jak ji nasadit?
Značka {texy}
představuje snadný způsob, jak v Latte
šablonách psát přímo v syntaxi Texy:
{texy}
You Already Know the Syntax
----------
No kidding, you know Latte syntax already. **It is the same as PHP syntax.**
{/texy}
Stačí do Latte nainstalovat rozšíření a předat mu objekt Texy
nakonfigurovaný podle potřeby:
$texy = new Texy\Texy;
$latte = new Latte\Engine;
$latte->addExtension(new Texy\Bridges\Latte\TexyExtension($texy));
Pokud je mezi značkami {texy}...{/texy}
statický text, tak se
přeloží pomocí Texy už během kompilace šablony a výsledek do ní
uloží. Pokud je obsah dynamický (tj. jsou uvnitř Latte značky),
zpracování pomocí Texy se provádí pokaždé při vykreslování
šablony.
Pokud je žádoucí Latte značky uvnitř vypnout, dá se to
udělat takto:
{texy syntax: off} ... {/texy}
Do rozšíření lze kromě objektu Texy předat také vlastní funkci a tak
umožnit předávat ze šablony parametry. Kupříkladu chceme mít možnost
předávat parametry locale
a heading
:
$processor = function (string $text, int $heading = 1, string $locale = 'cs'): string {
$texy = new Texy\Texy;
$texy->headingModule->top = $heading;
$texy->typographyModule->locale = $locale;
return $texy->process($text);
};
$latte = new Latte\Engine;
$latte->addExtension(new Texy\Bridges\Latte\TexyExtension($processor));
Parametry v šabloně předáme takto:
{texy locale: en, heading: 3}
...
{/texy}
Pokud chcete pomocí Texy formátovat text uložený v proměnné, můžete
použít filtr:
{$description|texy}