Datum jako služba – dobrý nápad?
- fh
- Člen | 18
Zdravím. Titulek vystihuje základní podstatu dotazu. Různé části systému vyžadují aktuální čas a z hlediska testování a DI by ho měly dostávat oproti jeho vytváření. Alespoň nepovinným setterem. Tak to bublá až nahoru, kde ho musím vytvořit. Z toho mi vyplývá, že i aktuální datum by mělo být jako služba a tak mohu také z jednoho místa dostat aplikaci do jiného času právě třeba pro účely testování. Je to dobrý nápad?
PS: Mohl bych pak kdekoliv v aplikaci pro porovnání aktuálního času
s jistotou používat ===
.
- Majkl578
- Moderator | 1364
Také jsem nad něčím podobným přemýšlel, pokud všude budu vytvářet nový čas, mohou vzniknout nekonzistence (ač to není moc pravděpodobné). Asi bych použil něco jako DateTimeProvider. Problém ale může být s neúmyslnou změnou zvenčí (někdo zapomene clone před modify a je to), protože DateTime není immutable. Takže a) možná spíš factory podle prototypu (vytvořeného při startu aplikace), b) freezable datetime?
- Filip Procházka
- Moderator | 4668
Určitě je to dobrý nápad. Napadlo mě něco jako
// return Nette\Datetime::from($this->getHeader('Request-Time'))
$datetime = $httpRequest->getTime();
- Majkl578
- Moderator | 1364
Zkusil jsem udělat jednoduchý Proof of Concept, je to na GitHubu. Co myslíte?
- fh
- Člen | 18
Majkl578 napsal(a):
Také jsem nad něčím podobným přemýšlel, pokud všude budu vytvářet nový čas, mohou vzniknout nekonzistence (ač to není moc pravděpodobné). Asi bych použil něco jako DateTimeProvider. Problém ale může být s neúmyslnou změnou zvenčí (někdo zapomene clone před modify a je to), protože DateTime není immutable. Takže a) možná spíš factory podle prototypu (vytvořeného při startu aplikace), b) freezable datetime?
Freezable DateTime se mi líbí. I když možná rovnou immutable. Otázka
je, jestli by všechny stav měnicí metody měly vracet klon nebo vyhazovat
výjimku? Pro jednodušší použití by se mi líbilo, kdyby vracely klon. Pak
by se docela pohodlně použila třeba metoda add()
. Akorát
původní add()
vrací DateTime i tak, aby byla fluent, což by
mohlo mást. Ale na to by si asi člověk zvyknul.
- Jan Tvrdík
- Nette guru | 2595
@fh: Mít čas jako služby se mi líbí.
@Majkl578: Metodu
IDateTimeProvider::getDateTimePrototype()
bych přejmenoval na
getDateTime()
. Prototyp je ten klonovaný DateTime (název
$dateTimePrototype
je tedy v pořádku).
- Majkl578
- Moderator | 1364
@Jan Tvrdík: Předpokládám, že to přejmenování jsi myslel naopak. Dávalo by to smysl, pokud by (aktuálně) getDateTime nevracelo klon.
@fh: Ale afaik nepřicházíš o možnost weak comparison, tj.
==
. Problém je, že PHP stále nemá immutable DateTime (do
5.5 se taky nedostalo). Otázka tedy je, jak ideálně vyřešit
zmražení daného DateTime objektu. Šance, že ten objekt někde
v aplikaci neúmyslně změníš, je relativně vysoká, právě kvůli
zrádnosti mutable rozhraní.
Uvažoval jsem nad něčím podobným, co nabízí Nette\FreezableObject, tj.
FreezableDateTime, to by asi šlo.
- Jan Tvrdík
- Nette guru | 2595
@Majkl578: To přejmenování jsem myslel tak, jak
jsem ho napsal. BaseControl::getControlPrototype()
taky
nevrací klon.
Jinak DateTimeImmutable
se do PHP 5.5 dostalo, viz https://github.com/….0beta1/NEWS.
Uvažovalo se o zrušení, ale nakonec k němu nedošlo, ne?
- fh
- Člen | 18
Majkl578 napsal(a):
…
@fh: Ale afaik nepřicházíš o možnost weak comparison, tj.==
. Problém je, že PHP stále nemá immutable DateTime (do 5.5 se taky nedostalo). Otázka tedy je, jak ideálně vyřešit zmražení daného DateTime objektu. Šance, že ten objekt někde v aplikaci neúmyslně změníš, je relativně vysoká, právě kvůli zrádnosti mutable rozhraní.
Uvažoval jsem nad něčím podobným, co nabízí Nette\FreezableObject, tj. FreezableDateTime, to by asi šlo.
Ale weak comparison je mi v tu chvíli asi ne moc užitečný, protože to jestli jsou dvě data stejného typu zjišťovat nepotřebuji. Šlo mi o porovnání zda čas je ten aplikační čas. I když spíš než o identitu jde o hodnotu, ale stejně. Bez identity budu hodnoty data porovnávat složitěji. A když bude immutable, mohu se na hodnotu spolehnout. Řekl bych že immutable je v tomto případě lepší než freezable, ale to je asi víc akademická debata. Imutable udělám z freezable v konstruktoru a je vyřešeno, to je pravda…
- Majkl578
- Moderator | 1364
@fh:
protože to jestli jsou dvě data stejného typu zjišťovat nepotřebuji
K tomu weak comparison neslouží.
Šlo mi o porovnání zda čas je ten aplikační čas.
Opravdu? A nezajímá tě spíš, jestli hodnota je stejná?
Bez identity budu hodnoty data porovnávat složitěji.
Jakto? Objekt není stejný, ale hodnoty ano. Tedy identita neprojde, ale weak comparison ano.
$a = new DateTime();
$b = clone $a;
var_dump($a === $b); // FALSE
var_dump($a == $b); // TRUE
Řekl bych že immutable je v tomto případě lepší než freezable
Souhlasím a vývojáři PHP taky, neshodli se ale na tom, jak to čistě implementovat (kandidát do 5.5 bylo DateTimeImmutable extendující DateTime, což ale nedává smysl a jiná cesta je naopak BC break, proto se to do 5.5 nedostalo).
- Filip Procházka
- Moderator | 4668
Položím vám záludnou otázku – koukali jste někdo, jak se to řeší v jiných jazicích/frameworcích? :)
- mkoubik
- Člen | 728
Podle mě to řešíte moc složitě, já používám toto (jen jako náhradu za volání konstruktoru) a funguje to skvěle:
class Calendar extends \Nette\Object implements ICalendar
{
/** @return \DateTime */
public function now()
{
return new \DateTime;
}
/** return \DateTime */
public function datetime($time)
{
return new \DateTime($time);
}
}
- Majkl578
- Moderator | 1364
Ještě ad DateTimeImmutable. Ačkoliv si myslím, že v PHP poměrně dost chybí, aktuální implementace je katastrofa vedoucí k BC breakům (proč jen mě to u PHP nepřekvapuje). Vyplnil jsem bug report s žádostí o odstranění z 5.5.
- fh
- Člen | 18
Majkl578: Hmm.. Tak to asi zmizi.. Zatim to teda v logu
neni. Na zaklade toho mailing listu je otazka jak to implementovat. Aby to tise
vracelo klony je teda kvuli LSP asi nevhodne. Asi by to melo hazet
v upravovacich metodach vyjimky a mit nejakou tu metodu
cloneMutable
, co by vratila klasicky DateTime
.
- Filip Procházka
- Moderator | 4668
enumag napsal(a):
@Filip Procházka: Můžeš nás zasvětit, znalče? :-)
Já přece nepsal, že to vím :)
Já to teď řeším tak, že mám volitelný argument u metod, kvůli testovatelnosti
public function foo($arg, \Datetime $now = NULL)
{
$now = $now ?: new \Datetime();
- Jan Tvrdík
- Nette guru | 2595
@Filip Procházka: Mám to podobně, ale mít to centrálně vyřešené jednou službou mi dává smysl.
- Filip Procházka
- Moderator | 4668
To rozhodně, proto jsem navrhoval kouknout ke konkurenci. Přece jenom, není potřeba vymýšlet kolo.
Nechtěl by autor vlákna sepsat RFC? :)
- fh
- Člen | 18
Filip Procházka napsal(a):
To rozhodně, proto jsem navrhoval kouknout ke konkurenci. Přece jenom, není potřeba vymýšlet kolo.
Nechtěl by autor vlákna sepsat RFC? :)
Jako RFC pro immutable DateTime do PHP? Šlo mi spíš o obecný přístup k času jako službě. Natolik to zmáknuté nemám:)