Jednou z novinek PHP 5.4 je typehint callable
.
Byla by to parádní věc, kdyby to tvůrci tak děsně nezprasili.
PHP typ callbable je pseudotypem, jehož hodnotou může být buď název metody či funkce (tj. řetězec) nebo dvojice třída/objekt a její metoda, tedy pole. V PHP se používá od pradávna, nicméně od verze 5.4 pro něj existuje typehint:
class Template
{
function registerHelper($name, callable $helper)
{
...
}
}
$template = new Template;
$template->registerHelper('date', 'Helpers::date');
Skvělé. Tedy až do chvíle, než to vyzkoušíte a PHP vás zdupne:
error: Argument 2 passed to Template::registerHelper() must be callable, string given
Aha, tak je to asi potřeba zapsat jako pole:
$template->registerHelper('date', ['Helpers', 'date']);
Výsledek je opět:
error: Argument 2 passed to Template::registerHelper() must be callable, array given
Ve skutečnosti PHP vadí to, že třída Helpers
neexistuje.
Totiž už během volání registerHelper
její přítomnost
vyžaduje. Typehint callable, narozdíl od všech jiných typehintů,
neověřuje jen formální platnost předaného argumentu, ale ujišťuje se,
že uvedená třída skutečně existuje a má zmíněnou metodu. Pokud třída
neexistuje, pokusí se ji načíst autoloadingem.
Což jednak zabíjí lazyloading – už samotné předání parametru s callbackem načte příslušnou třídu, která by se třeba jinak vůbec načítat nemusela.
A za druhé to generuje naprosto idiotské chybové hlášky. Což je
věc, na kterou jsem dosti citlivý. Ze zprávy
must be callable, string given
těžko někdo pochopí, že typ
string je použitý správně, jen neexistuje třída či metoda. Já bych to
chápal tak, že funkce neakceptuje řetězce. Přitom třeba funkce
call_user_func
ve stejné situaci generuje zcela smysluplné
chyby jako:
Warning: call_user_func() expects parameter 1 to be a valid callback, class 'Helpers' not found Warning: call_user_func() expects parameter 1 to be a valid callback, class 'Helpers' does not have a method 'date'
Na chybu jsem upozornil, bohužel Rasmus je se současným chováním nadmíru spokojen. Setrvávat na zavádějících chybových hláškách je projevem arogance a hlouposti: namísto opravy raději uvedou ve zmatek statisíce programátorů a připraví je o spoustu času. Nette Framework rozhodně zprasený typ callable používat nebude.
Komentáře
paranoiq #1
já prostě všude vyžaduji Nette\Callback. je to režie navíc (vytvoření jednoho objektu), ale dá se na to spolehnout a funguje to všude. nejen v 5.4. možná by v tomhle ohledu mohlo přitvrdit i Nette… nebo radši ne? (to by bylo BC breaků)
Jiří Soukup #2
Nechce se ti někdy přesedlat na jazyk, kde je koncentrace kreténů v core přeci jen menší? Obdivuji tvou trpělivost :)
Filip Procházka (@HosipLan) #3
Davídek je skrytý masochista, jako i my všichni :)
Pitrsonek #4
#2 Jiří Soukupe, Na co treba presedlat?
enumag #5
#4 Pitrsonku, Co třeba na Haxe? Dá se zkompilovat mimo jiné i do PHP. 😉
softice #6
#4 Pitrsonku, Clojure, Erlang, F#, Haskell, Javascript, Scala, Kotlin, Go, D v poslednej dobe vzniká mrte zaujimavých jazykov, stačí si len vybrať.
jlk #7
#6 softice, Javas…wat?
Ano, je možné psát s diakritikou ☹
Tori #8
Ještě by to šlo vysvětlit tak, že „callback“ !== „callable“, že callback musí být pouze syntakticky správný, kdežto callable i spustitelné. Ale pak by kromě is_callable (s implicitním autoloadingem) měla existovat i funkce is_callback (jen ověření syntaxe). Anebo naopak v zájmu konzistence k is_string přidat přepínač, aby akceptovala i desetinná čísla a objekty s metodou __toString.
David Grudl #9
#8 Tori, Pro ověření syntaxe lze použit
is_callable($var, true)
juzna.cz #10
Nezkoušel jsi, jaký dopad na výkonnost aplikací by mělo použítí
callable
v Nette? Byl by to opravdu problém? Kolik tříd by se muselo načíst „zbytečně“ (rozuměj kvůli včasné kontrole)? Kolik procet z již načítaných tříd to je?David Grudl #11
#10 juzna.czi, nezkoušel, ale nemyslím, že by byl nějak velký.
p4l4cl][n #12
Idealni by byly dva type hinty… callback a callable.. by resilo veskere problemy
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.