Matoucí zpráva: Argument passed to SmartCachingIterator::__construct must be…
- David Grudl
- Nette Core | 8227
Typická chyba v šabloně při použití makra
{foreach ...}
– člověk se překlepne a iteruje nad
neexistující proměnnou nebo proměnnou s hodnotou NULL. Nette vyhodí
výjimku:
Argument passed to SmartCachingIterator::__construct must be an array or interface Iterator provider, NULL given.
To je asi nejvíc matoucí výjimka celého frameworku ;) Vyhlašuju soutež na její přeformulování. Speciální bonus pro toho, kdo najde řešení zohledňující fakt, že SmartCachingIterator je třída existující nezávisle na LatteFilter a nějakých makrech.
- Petr Motejlek
- Člen | 293
Čím je tak strašně matoucí? Já vždycky tušil, co je špatně, když mi Laděnka hezky ukázala v tracu té výjimky, že za to může {foreach …}.
- Lopata
- Člen | 139
To je sice pravda, ale jak člověk čte rychle, toho překlepu si málokdy všimne. A ještě to umocňuje vlastnost lidskémo mozku podobné překlepy ignorovat. Takové chyby se pak hrozně těžce hledají a nejvíc naštvou. David má pravdu, že by ta vyjímka mohla být výřečnější…
Myslím, že asi nejlepší bude tam připsat doporučení, čím by to mohlo být způsobeno:
„Argument passed to SmartCachingIterator::__construct must be an array or interface Iterator provider, NULL given. It might be caused by a typo or unavailability of the desired variable in the template.“
To je, myslím, nejbezbolestnější…
- pekelnik
- Člen | 462
Daleko jasnější mi přijde:
<?php
'Invalid argument passed to foreach in template blemblem.phtml on line 80'
?>
Co myslíte?
Případnému doporučení ve formě požadovaného interfejsu se nebráním :)
Otázkou je zda se ve chvíli „spuštění“ šablony jsme schopni dostat k informacím o umístění v kódu zdrojové šablony… :|
Což mi připomíná jednu věc… zkusím ji sem napsat a uvidíme, ostatně to trochu souvisí…
Ve třídě LimitedScope na řádku 60 dochází pči chybě v šabloně k Parse Error ovšem člověk nemá šanci zjistit oč se jedná dokud před return v této funkci nepřidá
<?php
$code = func_get_arg(0);
file_put_contents(Environment::expand('%logsDir%/' . md5($code) . '-' . (string) microtime(TRUE) . '.php'), $code);
?>
Možná by stálo za to v takovém případě celý kus kódu zobrazit/uložit do logů. (V závislosti na módu)
Editoval pekelnik (12. 1. 2010 12:32)
- Petr Motejlek
- Člen | 293
Asi takhle: SmartCachingIterator by v žádném případě neměl tušit něco o tom, že byl volán z nějaké šablony. Měl by teda vyhodit vyjímku s textem, že obdržel null jako parametr. Potom by mělo něco, co renderuje tu šablonu, odchytit takovou výjímku, a přilepit k ní, že se jedná o chybu vyvolanou při renderování šablony na řádku tom a tom… Ergo nemám nic proti tomu, aby hláška vyjímky obsahovala řádek v šabloně, ale mám něco proti tomu, aby takovou vyjímku vyhazoval přímo už SmartCachingIterator ;).
- David Grudl
- Nette Core | 8227
Petr Motejlek napsal(a):
Potom by mělo něco, co renderuje tu šablonu, odchytit takovou výjímku, a přilepit k ní, že se jedná o chybu vyvolanou při renderování šablony na řádku tom a tom…
K tomu není potřeba ji odchytávat a modifikovat, informaci o jméně šablony (byť z cache) a číslu řádku obsahuje tak i tak.
Souhlasím, že SmartCachingIterator nemůže předpokládat použití v šabloně, nakonec proto jsem tohle téma otevíral, jinak by věc byla triviální. Takže chce to dostatečně šikovnou pragmatickou formulaci. Něco s dovětkem …probably you have passed NULL in foreach nebo tak.
- David Grudl
- Nette Core | 8227
Mimochodem, podobná věc je vypsání {$people}
, kde $people je
pole. Na to vyhodí htmlspecialchars:
Warning: htmlspecialchars() expects parameter 1 to be string, array given
které taky není úplně cool, nehledě na to, že SmartCachingIterator(NULL) končí výjimkou, kdežto tohle varováním. Chtělo by to sjednotit. Tady je věc jednodušší v tom, že bycha se objevuje v TemplateHelpers::escapeHtml(), kde už souvislost se šablonou lze předpokládat.
- Jan Tvrdík
- Nette guru | 2595
Co vytvořit potomka SmartCachingIterator
speciálně pro
foreach cyklus:
class TemplateForeachIterator extends SmartCachingIterator
{
public function __construct($iterator)
{
try {
parent::__construct($iterator);
} catch (InvalidArgumentException $e) {
throw new InvalidArgumentException('Invalid argument passed to foreach');
}
}
}
- Petr Motejlek
- Člen | 293
Pokud je SmartCachingIterator univerzalni (tj. nezavisi na sablone), je IMHO pragmaticke, aby o ni vubec netusil. Z tohohle duvodu se napr. vyjimky v Jave umi na sebe navazovat, aby bylo jasne, co zpusobilo co, a vubec jsme se o takove „hlouposti“ nemuseli bavit…
SmartCachingIterator by mel vyhodit nejakou vyjimku podobnou IllegalArgumentException(„Null passed to SmartCachingIterator.“), a tuhle vyjimku by si melo odchytit to, co renderuje tu sablonu. To by potom melo vytvorit neco jako TemplateProcessingException(„While processing the template file bleble.phtml on line X there was an exception thrown.“, IllegalArgumentException(„Null passed to SmartCachingIterator“).
Tohle se mi zda jako dostatecne primitivni, pragmaticka a funkci koncepce, ktera se muze pouzit naprosto kdekoliv.
- Petr Motejlek
- Člen | 293
Ondřej Mirtes napsal(a):
A Laděnka ukazuje Stack trace, tak to snad není potřeba :)
A s tím taky souhlasím.
- Jakub Lédl
- Člen | 55
Já bych nechal původní chybovou hlášku, jelikož mi přijde naprosto v pohodě.
Je tam SmartCachingIterator (c'mon, každý, kdo dělá v Nette a někdy koukal do přeložených šablon VÍ, že {foreach} používá SmartCachingIterator), je tam popsán důvod chyby (očekávám pole|Iterator, šoupli mi NULL) a Nette\Debug ukáže, kde k chybě došlo.
NEBO: Foreach (a je jedno, jestli foreach (), nebo {foreach}, začátečníka to nezmate) has to iterate over an array or an Iterator interface implementation, but NULL was given.
- Jakub Lédl
- Člen | 55
začátečníka to nezmate
bylo myšleno tak, že foreach
může být chápáno jak jako
foreach () {}
pokud mám člověk PHP šablony, či jako
{foreach}...{/foreach}
pokud používá LatteFilters. Musí to
pochopit i absolutní debil.
- Honza Kuchař
- Člen | 1662
Já bych to neměnil. Ale uznávám, že mě to jako začátečníka zmátlo. Udělal bych, jak tu bylo plánováno odkaz do wiki na webu nette.org, kde bych se dozvěděl více informací a třeba o tom, kdy ta chyba může nastat.
- Jakub Lédl
- Člen | 55
Co toto znění:
Foreach statement cannot operate with variables of type ‚X‘ because ‚X‘ doesn't implement the Iterator interface.
Podle mě krátké, výstižné a společně s výstupem z Nette\Debug naprosto všeříkající (OK, není to tak úplně moje dílo, je to lehce upravená hláška, kterou vygeneruje C# kompilátor).
Uznávám, že tato hláška je možná příliš obecná, jelikož pokud standartnímu foreachi naservíruju objekt, tak si jeho členské proměné interně převede na pole a klidně iteruje přes ně (pro mě naprosto nepochopitelné chování). Ale řekl bych, že právě toto je jedna z věcí, které by se měl začátečník, pokud tuto prasárnu dělá, odnaučit! Vždyť je to naprosto exemplární bad-code smell.
- Filip Procházka
- Moderator | 4668
Jakub Lédl napsal(a):
Foreach has to iterate over an array or an Iterator interface implementation, but NULL was given.
+1
- Petr Motejlek
- Člen | 293
Jakub Lédl napsal(a):
Uznávám, že tato hláška je možná příliš obecná, jelikož pokud standartnímu foreachi naservíruju…
Já se už delší dobu domnívám, že naprostá většina automatických přetypování je špatná ;).
- Petr Motejlek
- Člen | 293
Ondřej Mirtes napsal(a):
A je to vyřešené :o)
Já bych neřekl, že je to vyřešené ;). Spíš se to chová jako přilepit utrženou nohu izolepou k židli. Ale což, hlavně, že jste spokojení :D.