Za méně křiku v kódu

před 2 lety od David Grudl  

Coding style Nette prochází drobnou úpravou: pro konstanty tříd se nově používá notace PascalCase místo původní SCREAMING_SNAKE_CASE.

Tradice používání velkých písmen pro konstanty pochází z jazyka C, kde se takto označovaly tzv. makrokonstanty preprocesoru. Bylo užitečné nepřehlédnutelně odlišit kód pro parser od kódu pro preprocesor. PHP tohle odlišení nepotřebuje jelikož preprocesor nemá. Naopak přílišné zvýraznění konstant je kontraproduktivní. Proč by měla konstanta křičet a upozorňovat na sebe, být vyčnívajícím elementem v toku programu? Není k tomu důvod.

Příklad reálného kódu s SCREAMING_SNAKE_CASE konstantami, které agresivně vyčnívají z kódu a také se hůře čtou:

foreach (self::SYMBOL_TO_NAME as $symbol => $name) {
	$idx = self::ACTION_BASE[$state] + $symbol;
	if (($idx >= 0 && $idx < count(self::ACTION) && self::ACTION_CHECK[$idx] === $symbol
			|| $state < self::YY_2_TBLSTATE
			&& ($idx = self::ACTION_BASE[$state + self::NUM_NON_LEAF_STATES] + $symbol) >= 0
			&& $idx < count(self::ACTION) && self::ACTION_CHECK[$idx] === $symbol)
		&& self::ACTION[$idx] !== self::UNEXPECTED_TOKEN_RULE
		&& self::ACTION[$idx] !== self::DEFAULT_ACTION
		&& $symbol === 0
	) {
		return true;
	}
}

Příklad téhož kódu s PascalCase konstantami, který působí mnohem kompaktněji:

foreach (self::SymbolToName as $symbol => $name) {
	$idx = self::ActionBase[$state] + $symbol;
	if (($idx >= 0 && $idx < count(self::Action) && self::ActionCheck[$idx] === $symbol
			|| $state < self::Yy2Tblstate
			&& ($idx = self::ActionBase[$state + self::NumNonLeafStates] + $symbol) >= 0
			&& $idx < count(self::Action) && self::ActionCheck[$idx] === $symbol)
		&& self::Action[$idx] !== self::UnexpectedTokenRule
		&& self::Action[$idx] !== self::DefaultAction
		&& $symbol === 0
	) {
		return true;
	}
}

Kompatibilita

Nette samozřejmě dbá na zpětnou kompatibilitu. Všechny veřejné konstanty nadále zůstávají také v původní podobě a slouží jako aliasy pro preferované PascalCase konstanty. Budou existovat i v příští major verzi a budou mít příznak @deprecated.

Všechny nově přidané konstanty tříd už jsou pouze ve variantě PascalCase. Globální konstanty Nette nepoužívá.

Enumerations

PHP 8.1 přináší výčtové typy, které se budou jednou používat i v Nette. Dříve se enumy napodobovaly pomocí konstant. Samotná dokumentace PHP pro „enum cases“ používá PascalCase notaci, taktéž PHP-FIG nebo dřívější experimentální implementace SplEnum.

Výčty jsou v podstatě syntactic sugar pro konstanty, z pohledu PHP není mezi „enum case“ a třídní konstantou žádný rozdíl. A proto kombinovaní PascalCase enumů a SCREAMING_SNAKE_CASE konstant by vypadalo nekonzistentně, což je dalším důvodem pro změnu stylu zápisu konstant.

Jak změnit vlastní kód?

Každá kosmetická změna vyvolá vždy spoustu nevole. Ale pokud zkusíte měsíc PascalCase konstanty používat, budete z nich nadšeni a nebude cesty zpět. A budete chtít zavést novou notaci i do vlastního kódu. Jak na to? Ideální cestou je přejmenovat konstanty v PhpStormu pomocí funkce Refactor > Rename . Nainstalujte si také plugin String Manipulation a přidělte mu v nastavení klávesovou zkratku pro Switch Case > To Pascal Case.

Pak bude stačit umístit kurzor na konstantu, stisknout Ctrl-F6 (rename) a následně zkratku pro To Pascal Case a PhpStorm změní konstantu v celém projektu.

Happy coding!

Komentáře

  1. Kombinovat PascalCase výčty se SCREAMING_SNAKE_CASE konstantami by působilo nekonzistentně, tudíž i to je důvod pro změnu stylu zápisu konstant.

    Naopak, tohle je důvod zůstat u roky zažitého standardu, protože enumy mohou obsahovat konstanty a díky tomu snadno odliším k čemu přistupuji (MyEnum::CONST vs MyEnum::SomeCase).

    před 2 lety · replied [2] Rick Strafy
  2. #1 Casper Presne to mi napadlo ked som to cital, ze preco ten medzi-krok prave teraz, ked prisli enumy kde je ten zapis MyEnum::SomeCase, a ak sa z nejakej triedy bude robit v buducnosti enum, tak to bude BC break a pravdepodobne sa bude musiet vymyslat novy naming.

    Napr. ContentType (nie uplne asi najlepsi priklad kvoli custom content types) – ale ak by sa nieco take menilo na enum, zmeni sa tomu typ a ak su tam public property, rozbije to api, preto mi pride dost nestastne to rozhodnutie prebrat syntax enumov, trochu v tom bude chaos odlisovat enum od konstanty a navyse ak nette bude podporovat enumy, ten BC break pride zase.

    Napriklad nette/forms to este nema prepisane, co by bolo dobre asi nechat tak ako to je, pretoze v projektoch sa pouzivaju hlavne Form::CONST, a pri php8.1 by to mohlo byt ako FormRule::MaxLength.

    Mozno takych samostatnych tried ako ContentType je minimum, no aj tak, ak by napriklad nette4 potrebovalo aspon php8.1, mohlo by to byt cistejsie a neprinieslo by to nekonzistentnost, ze nette/* budu jedine kniznice ktore maju naming konstant ako enumov.

    před 2 lety · replied [3] David Grudl [4] Taco
  3. #2 Rick Strafy třída, která se může proměnit na enum, je v Nette/Latte pokud se nepletu pouze jedna. Zmíněný Latte\ContentType. A tím, že má konstanty v notaci PascalCase, tak právě naopak k BC breaku nedojde.

    Prostě za pár let až bude Latte minimálně pro PHP 8.1, tak se změní class ContentType {} na enum ContentType {}, typy u metod, kam se hodnota předává, ze string na ContentType, a hotovo, uživatel si ani nevšimne.

    před 2 lety
  4. #2 Rick Strafy Asi mi uniklo, proč že je třeba „odlišovat enum od konstanty“?

    před 2 lety
  5. https://www.php.net/…onstants.php
    By convention, constant identifiers are always uppercase.

    No aspoň se seznámím s composerem a vytvořím si nějaký postz install script, který ty konstanty opraví :)

    před 2 lety
  6. Vyzkoušel jsem psát konstanty v PascalCase a je to návykové – po týdnu už není cesty zpět. Sbohem SCREAMING_SNAKE_CASE, který jsem používal cca 15 let.

    před 2 lety

Chcete-li odeslat komentář, přihlaste se