Booleovské parametry u metod
- dmajda
- Člen | 22
V různých metodách Nette se občas předávají booleovské paramety,
u kterých není při pohledu na volající kód zřejmý jejich význam
(případně význam zřejmý je, ale plete se, co znamenají hodnoty
true
a false
). Takovéhle používání booleanů
není moc vhodné a mate uživatele, viz třeba Try to avoid having BOOL function parameters.
Zatím jsem narazil na následující případy (ale určitě jich bude víc):
$form->setAction($action, $isPost = NULL)
Zde by IMO bylo hezčí boolean odstranit a zavést separátní metodu
setMethod
, případně aspoň umožnit místo $isPost
psát rovnou název akce nebo předdefinovanou konstantu pro ni.
$httpRequest->getRemoteAddress($dns = FALSE)
Tady se podle hodnoty parametru vrací buď
$_SERVER['REMOTE_ADDR']
nebo $_SERVER['REMOTE_HOST']
(modulo nějaká menší magie s případným vytvářením druhé proměnné).
To jsou dvě různé věci a lepší by bylo je mít ve zvláštních metodách
(tj. getRemoteAddress
a getRemoteHost
).
$httpResponse->setHeader($name, $value, $replace = TRUE);
Parametr replace by bylo myslím lepší nahradit nějakou konstantou. Být
to v Javě, C# apod., dal bych tam místo booleanu
enum { REPLACE, ADD }
.
- David Grudl
- Nette Core | 8218
Vítej na fóru!
To je velmi dobrá poznámka. Už dřív jsem se pokusil na řadě míst
TRUE/FALSE/NULL nahradit (příklad),
ale má to svá úskalí. Tvé příklady jsou poměrně jasné, setMethod a
getRemoteHost přidám. Stejně tak setHeader
by se dalo
rozšířit do dalších metod appendHeader
a
deleteHeader
(tedy až to bude
možné).
V Nette se nejčastějí bool proměnná používá pro rozhodnutí, jestli má metoda vyhodit výjimku nebo vrátit FALSE. Taková obdoba vykřičníku v Ruby, nemýlím-li se.
Component::lookup($type, $need = TRUE)
Component::lookupPath($type, $need = TRUE)
ComponentContainer::getComponent($name, $need = TRUE)
Environment::getService($name, $need = TRUE)
ServiceLocator::getService($name, $need = TRUE)
Application::getService($name, $need = TRUE)
PresenterComponent::getPresenter($need = TRUE)
FormControl::getForm($need = TRUE)
Session::configure(array $config, $throw = TRUE)
Některé použití odpovídá konvencím PHP u obdobných metod:
HttpResponse::setHeader($name, $value, $replace = TRUE)
HttpResponse::setCookie($name, $value, $expire, $path = NULL, $domain = NULL, $secure = NULL)
HttpResponse::deleteCookie($name, $path = NULL, $domain = NULL, $secure = NULL)
Session::setCookieParams($path, $domain = NULL, $secure = NULL)
Debug::dump($var, $return = FALSE)
a pak jsou tu zbývající metody, u některých by se určitě hodilo najít lepší řešení:
ComponentContainer::getComponents($deep = FALSE, $type = NULL)
Html::getIterator($deep = FALSE)
Debug::enable($level = E_ALL, $logErrors = NULL, $sendEmails = FALSE)
Environment::setVariable($name, $value, $expand = TRUE)
Environment::loadConfig($file = NULL, $useCache = NULL)
Form::addGroup($label = NULL, $setAsCurrent = TRUE)
Form::validate($breakOnFailure = FALSE)
Rules::toggle($id, $hide = TRUE)
Html::setName($name, $isEmpty = NULL)
Html::insert($index, $child, $replace = FALSE)
Session::destroy($removeCookie = TRUE)
User::signOut($clearIdentity = FALSE)
User::setExpiration($seconds, $whenBrowserIsClosed = TRUE, $clearIdentity = FALSE)
- dmajda
- Člen | 22
David Grudl napsal(a):
V Nette se nejčastějí bool proměnná používá pro rozhodnutí, jestli má metoda vyhodit výjimku nebo vrátit FALSE. Taková obdoba vykřičníku v Ruby, nemýlím-li se.
Jen na okraj: Takhle vykřičník používají spíš Rails než samotné
Ruby, v Ruby typicky (ale ne vždy) značí destruktivnost operace
("ABC".downcase
vytvoří nový řetězec,
"ABC".downcase!
modifikuje původní – rozdíl je vidět,
mám-li na něj referenci i odjinud).
Component::lookup($type, $need = TRUE) Component::lookupPath($type, $need = TRUE) ComponentContainer::getComponent($name, $need = TRUE) Environment::getService($name, $need = TRUE) ServiceLocator::getService($name, $need = TRUE) Application::getService($name, $need = TRUE) PresenterComponent::getPresenter($need = TRUE) FormControl::getForm($need = TRUE) Session::configure(array $config, $throw = TRUE)
Tady je IMO potřeba mít znalost o typickém use-case. Přijde mi, že
u těchhle (vesměs vyhledávacích) metod bude mít jejich volající typicky
znalost o existenci vyhledávaného objektu a jeho nenalezení bude pro něj
překvapením, což by odpovídalo výjimce. Ale zas tak můžou vznikat
prázdné catch {} tam, kde nenalezení bude typické. Těžko říct, zda tady
ty parametry vyházet. Asi by bylo dobré koukat, jestli vůbec někdo někde
u té které metody používá $need = FALSE
.
Některé použití odpovídá konvencím PHP u obdobných metod:
HttpResponse::setHeader($name, $value, $replace = TRUE) HttpResponse::setCookie($name, $value, $expire, $path = NULL, $domain = NULL, $secure = NULL) HttpResponse::deleteCookie($name, $path = NULL, $domain = NULL, $secure = NULL) Session::setCookieParams($path, $domain = NULL, $secure = NULL) Debug::dump($var, $return = FALSE)
Tady nadhodím tématický odkaz o tom, že API pod sebou není vždy žádoucí slepě kopírovat: http://www.acmqueue.com/modules.php?…
BTW u Debug::dump
by se IMO víc hodilo, kdyby jako návratovou
hodnotu vrátil dumpnutý objekt – když bych měl třeba kód
f($a, $b, g($x, $y))
a chtěl si dumpnout výsledek fce
g
, stačilo by mi vložit Debug::dump
okolo ní.
V současné podobě je nutné ji z výrazu vytrhnout a dumpnout bokem.
Situaci podobnou téhle jsem zažil mockrát; situaci, kdy bych chtěl mít dump
v ruce, jsem nezažil nikdy (když pominu psaní nástrojů podobných Laděnce
kdysi dávno).
a pak jsou tu zbývající metody, u některých by se určitě hodilo najít lepší řešení:
ComponentContainer::getComponents($deep = FALSE, $type = NULL) Html::getIterator($deep = FALSE) Debug::enable($level = E_ALL, $logErrors = NULL, $sendEmails = FALSE) Environment::setVariable($name, $value, $expand = TRUE) Environment::loadConfig($file = NULL, $useCache = NULL) Form::addGroup($label = NULL, $setAsCurrent = TRUE) Form::validate($breakOnFailure = FALSE) Rules::toggle($id, $hide = TRUE) Html::setName($name, $isEmpty = NULL) Html::insert($index, $child, $replace = FALSE) Session::destroy($removeCookie = TRUE) User::signOut($clearIdentity = FALSE) User::setExpiration($seconds, $whenBrowserIsClosed = TRUE, $clearIdentity = FALSE)
Mám pocit, že ve většině případů by pomohlo rozdělení na víc funkcí, ale je mi jasné, že to zas zvyšuje velikost API, takže to také není ideální.
Škoda že PHP neumí keyword parameters jako Python, to by tady moc pomohlo :-(
- David Grudl
- Nette Core | 8218
dmajda napsal(a):
Jen na okraj: Takhle vykřičník používají spíš Rails než samotné Ruby, v Ruby typicky (ale ne vždy) značí destruktivnost operace (
"ABC".downcase
vytvoří nový řetězec,"ABC".downcase!
modifikuje původní – rozdíl je vidět, mám-li na něj referenci i odjinud).
Díky, konečně v tom mám jasno.
Tady je IMO potřeba mít znalost o typickém use-case. Přijde mi, že u těchhle (vesměs vyhledávacích) metod bude mít jejich volající typicky znalost o existenci vyhledávaného objektu a jeho nenalezení bude pro něj překvapením, což by odpovídalo výjimce. Ale zas tak můžou vznikat prázdné catch {} tam, kde nenalezení bude typické. Těžko říct, zda tady ty parametry vyházet.
V rámci frameworku jde o typický vzor, což existenci parametrů ospravedlňuje a nechal bych je tam.
Tady nadhodím tématický odkaz o tom, že API pod sebou není vždy žádoucí slepě kopírovat: http://www.acmqueue.com/modules.php?…
Koukám, že máš na všechno odkaz :-)
BTW u
Debug::dump
by se IMO víc hodilo, kdyby jako návratovou hodnotu vrátil dumpnutý objekt – když bych měl třeba kódf($a, $b, g($x, $y))
a chtěl si dumpnout výsledek fceg
, stačilo by mi vložitDebug::dump
okolo ní. V současné podobě je nutné ji z výrazu vytrhnout a dumpnout bokem.
Výborný nápad, dump upravím.
Mám pocit, že ve většině případů by pomohlo rozdělení na víc funkcí, ale je mi jasné, že to zas zvyšuje velikost API, takže to také není ideální.
To je vždycky otázka, obzvlášť u PHP, kde se volí mezi pohodlím a rychlostí. Každopádně třeba správu cookies a HTTP hlaviček se chystám (už dva roky) předělat.
- phx
- Člen | 651
Kdyz jsme u te rychlosti a pohodli tak ve vetsi app musi syntakticky sugar delat mozna i vetsi % zateze. Nevim netestoval jsem to, je to jen myslenka. Je to totiz silne navikove a kdyz to pouziva clovek vsude tak nevim nevim.
Napada me, ze by na to slo udelat neco jako u sablon. Prohnat to 1× pres
nejaky formatovac, ktery by z $class->metod
udelal
$class->getMetod()
. Otazka zni zda by to vykonove nejak pomohlo
a jak hodne. Pokud by to byly jednotky % tok to asi nema cenu.
Editoval phx (23. 10. 2008 19:04)
- Ondřej Mirtes
- Člen | 1536
Upravil jsem stránku HttpRequest v dokumentaci, getRemoteAddress(true) mi už nezafungovalo, místo něj jsem ve zdrojáku „objevil“ getRemoteHost() :)