Funkce callback()
- David Grudl
- Nette Core | 8228
Sice se to zcela vymyká zbytku frameworku, ale co vytvořit jednoduchou
funkci callback()
, aby fungovalo:
$form->onSubmitted[] = callback($this, 'method');
Také lze přidat na Control (asi méně intuitivní):
$form->onSubmitted[] = $this->callback('method');
- Patrik Votoček
- Člen | 2221
proč to?
$form->onSubmit[] = array($this, 'method');
je pořád méně písmenek a tak je to napsáno rychleji… (nezpomalovalo by to zbytečně?)
- Ondřej Brejla
- Člen | 746
enoice napsal(a):
cb($this, "method");
? :-)
To je dost „nesamopopisné“, nic neříkající fce cb()
.
Když už, tak callback()
. Ale taky se mi zdá, že je to
zbytečné.
- Patrik Votoček
- Člen | 2221
enoice napsal(a):
cb($this, "method");
? :-)
To by mohlo místo callback evokovak ke CurlyBrackets… :-/
- ViliamKopecky
- Nette hipster | 230
Jod napsal(a):
Malo by to hádzať CallbackException aby každý vedel, že je to callback :)))
tak tak, házelo by to exception už při vytvoření callbacku, ne až při jeho použití.
- vlki
- Člen | 218
Ta kontrola callbacku už při vytvoření je lákavá…
Plus také to, že PHP 5.2.0 a 5.2.1, myslím, neumí callbacky na statické
funkce pomocí Class::method
, ale jen
array('Class', 'method')
. Nemuselo by se toto tedy řešit až na
úrovní volání callbacku (pro což myslím vznikla i funkce fixCallback),
ale šlo by přímo v této funkci.
- Honza Kuchař
- Člen | 1662
Já jsem pro. Když jsem začínal na Nette, tak zrovna ty callbacky byly pro mě naprosto nepochopitelné.
Asi nějak takhle:
Proč mám vytvářet nějaké pole, když chci callback?!
- Majkl578
- Moderator | 1364
Jod napsal(a):
Podla mňa, keď bude možné zadávať callback ako pole a aj cez funkciu nejakého Componentu nič sa tým nepokazí.
Jak by vypadalo toto v praxi?
$form = new AppForm;
//...
$form->onSubmit($this, 'fooFormSubmitted');
Myšleno jako zkratka pro callback při použítí přímo u formuláře.
Editoval Majkl578 (15. 10. 2009 12:25)
- jasir
- Člen | 746
Jsem pro vytvoření funkce callback, implementace pomocí globální funkce je pragmatická.
- + možnost kontroly správnosti již při vytvoření callbacku se může ukázat jako velmi produktivní
- + přehlednější kód
- + zachování možnosti tvorby callbacku pomocí
array($this, 'method')
- – zpomalení, předpokládám ale že neměřitelné
Editoval jasir (19. 10. 2009 15:52)
- paranoiq
- Člen | 392
jsem pro přidání. hlavně pokud to pomůže odstranit magickou funkci fixCallback(). současný zápis callbacků, kdy se u statických metod předává nevalidní řetězec a až posléze se někde skrytě opraví na validní callback může být matoucí
určitě je lepší přehledný a čitelný kód, než nějaká dogmatická objektovost za každou cenu
- amsys
- Člen | 20
Když už jsme u fixCallback tak to jen tak snadno nezmizí, globální funkce callback bude vracet vždy pole, jenže v tom případě se to bude prohánět fixCallback i napopodruhé protože nemáme jak jednoduše dát vědět, že už to již jednou bylo upravené, ale stejně to asi nebude znát na výkonu.
- kravčo
- Člen | 721
paranoiq napsal(a):
jsem pro přidání. hlavně pokud to pomůže odstranit magickou funkci fixCallback(). současný zápis callbacků, kdy se u statických metod předává nevalidní řetězec a až posléze se někde skrytě opraví na validní callback může být matoucí
Funkcia fixCallback()
neopravuje neplatne zadané callbacky, ale
umožňuje podporu nižších verzií PHP tým, že platné
callbacky prepíše do podoby, ktorú zvládnu. Tým umožňuje písať
aplikácie prenositeľné medzi verziami PHP.
- David Grudl
- Nette Core | 8228
S odstupem času jsem dnes funkci callback()
implementoval.
Nejlepší bude ji ověřit praxí, odstranit se dá vždycky.
Nejprve pár nesouvislých bodů, které jsem měl na mysli během zvažování způsobu implementace:
- který zápis callbacku by v PHP vypadal srozumitelněji?
array($a, $b)
vs.callback($a, $b)
- PHP 5.3 zavádí closures, které lze volat přes
$callback($arg, ...)
- klasické callbacky lze volat pouze přes
neobjektové
call_user_func($callback, $arg, ...)
- pokud se volání nezdaří, vygeneruje se pouze warning (!)
- striktnost lze zajistit pouze důsledným kontrolováním
přes
is_callable()
- do verze PHP 5.2.1 nelze použít zápis
$callback = 'Trida::metoda'
, je třeba pole - před verzí PHP 5.3 nelze volat objekt s magickou
metodou
__invoke
- kontrola callbacků v okamžiku vytvoření může být výhodná při vývoji, může však načítat třídy, které nebudou při běhu nakonec potřeba
Implementace znamenala comeback pro třídu Nette\Callback
;)
Funkce callback
je pouze její továrničkou. Což jde mimo coding
styles frameworku, je to vlastně jediná veřejná funkce v celém frameworku.
(Aby nebyla sama, přidal jsem ji ještě funkci dump()
volající
Debug::dump
).
Zdá se mi, že tato úprava framework trošku pročistila. Takže snad je to krok správným směrem.
- David Grudl
- Nette Core | 8228
Nad tímhle furt váhám, protože fakt nemám rád, když se jedna věc dá udělat dvěma způsoby. A __invoke existovat musí. Ale asi jsem našel argument pro invoke(), protože ani v PHP 5.3 nejde udělat:
$methodInfo = new MethodReflection('B', 'foo');
$methodInfo->getCallback()(...) // nelze
$methodInfo->callback(...) // nelze; callback je property getCallback()
$methodInfo->callback->invoke(...)
tudíš se musí psát __invoke.
- redhead
- Člen | 1313
nebo když už je tam invokeArgs (nebo jak to je) proč neudělat prostě invoke a pod to dát i podporu pro args, který se zjistí přes func_get_args (jako vlastně nepovinnej parametr) seskupit to do jedné metody. Hm?
Jinak přesně nad spojením __invoke do invoke jsem včera přemejšlel, invoke vypadá v kódu rozhodně líp :D
- Filip Procházka
- Moderator | 4668
Davide, malá chybka:)
PHP 5.2.4–2ubuntu5.9 with Suhosin-Patch 0.9.6.2 (cli) (built: Nov 26 2009
14:00:44)
Copyright © 1997–2007 The PHP Group
Zend Engine v2.2.0, Copyright © 1998–2007 Zend Technologies
with Xdebug v2.0.2, Copyright © 2002–2007, by Derick Rethans
<?php
class Trida
{
function fce1()
{
return call_user_func_array(array($this, 'fce2'), func_get_args());
//Fatal error: func_get_args(): Can't be used as a function parameter
}
function fce2()
{
var_dump(func_get_args());
}
}
$t = new Trida();
$t->fce1('arg1', 2, 3.0);
- David Grudl
- Nette Core | 8228
Neříkám, že by to mělo fungovat, ale že se člověk psaní __invoke() stejně nevyhne a tak má smysl vytvořit alias invoke().
HosipLan napsal(a):
Davide, malá chybka:)
Na kterém řádku konkrétně?
- Filip Procházka
- Moderator | 4668
Třída callback
85: return call_user_func_array($this->cb, func_get_args());
Nette/Forms/Controls/TextBase.php – tady IMHO nemá být komentář
56: $value = (string) $filter/*->__invoke*/($value);
Nette/ServiceLocator.php – přehrocené komentáře?
139: $service = $factory/**/->__invoke/**/($options);
Nette/Templates/BaseTemplate.php – přehrocené komentáře?
126: $content = $filter/**/->__invoke/**/($content);
Nette/Templates/BaseTemplate.php – přehrocené komentáře?
193: $helper = $loader/**/->__invoke/**/($lname);
když nad tím tak přemýšlím, asi je to tam kvůli převaděči na 5.3
:)
každopádně v Nette/Templates/Filters/LatteMacros.php je nemáš
271: ->__invoke($content, $modifiers);
Nette/Web/Session.php – zase bez komentářů
87: $verKey = (string) callback($this->verificationKeyGenerator)->check('Verification key generator')->__invoke();
Tak snad jsou to všechny nejasnosti :)
Editoval HosipLan (20. 1. 2010 17:40)
- David Grudl
- Nette Core | 8228
Komentáře jsou kvůli převaděči na PHP 5.3. Zeptám se jinak: narazil jsi na nějakou chybu, nebo máš jen dojem, že je tam chyba? ;)
- Filip Procházka
- Moderator | 4668
volání
call_user_func_array($whatever, func_get_args());
způsobí fatal error, to ostatní jsou víceméně překlepy až na ten druhý kód co jsem poslal kde je invoke zakomentované úplně
//edit: Teď jsem si to prohlédl pořádně a máš pravdu s těmi komentáři, každopádně ten fatal je oveřenej :)
Editoval HosipLan (20. 1. 2010 19:49)
- Filip Procházka
- Moderator | 4668
vidím že už jsi to vzorově opravil :) ta verze co je na githubu teď už funguje :)
- David Grudl
- Nette Core | 8228
Vždy prosím zkus, jestli se to týká aktuální verze. Tenhle „bug“ existoval asi hodinu po prvním zveřejnění třídy Callback, což je už mimo mou rozlišovací schopnost a paměť.
- nAS
- Člen | 277
Díky za info, o curryingu jsem neslyšel, rád jsem si doplnil vzdělání.
I tak mi ale přijde, že na základní věci by bylo jednodušší využít callbacků. Viz srovnání:
class MyClass
{
public function doSomething($param)
{
// do something
}
public function foobar()
{
// pomoci curryingu
$this2 = $this; // http://bugs.php.net/bug.php?id=49543
$callback = function () use ($this2) { $this2->doSomething('param'); };
// pomoci callbacku
$callback = callback($this, 'doSomething')->setArgs('param');
}
}
Je jasné, že na případy, kdy se přidávají parametry i při vytváření i při volání je mnohem praktičtější currying, ale mě v naprosté většině případů bude stačit jednoduchý callback. Krom toho je to použitelné i pro lidi s PHP 5.2.
- v6ak
- Člen | 206
Já bych byl spíše pro nějaký wrapper mimo Callback, něco jako:
<?php
function fixArgs($callback, $args){
return function()use($callback, $args){
return call_user_func_array($callback, $args);
}
}
?>
Za případné chyby a nedostatky v odsazení se předem omlouvám, píšu
z mobilu.
Samozřejmě, dají se vymyslet mnohé další věci jako třeba varargs místo
array $args a spojování parametrů. Hlavní myšlenka ale je, že to nemusí
být jako vlastnost callbacku.
- jakubkulhan
- Člen | 55
Když currying, udělal bych ho tak, jak funguje ve funkcionálních
jazycích jako Haskell, OCaml atp. Obal nativního callbacku by při zavolání
zkontroloval, jestli dostal alespoň tolik argumentů, kolik nativní callback
očekává (to by se asi muselo kontrolovat reflexí). Dostal-li by, zavolal by
nativní callback a vrátil jeho návratovou hodnotu. Dostal-li by méně,
vrátil by „curryfikovanou“ obálku (callback + některé z jeho
argumentů). Nemá cenu podobnými hračkami zpomalovat přímo
Callback
, protože se to využije asi ne na moc místech. Místo
toho by pro curryfikované funkce mohla být třída, řekněme,
CurriedCallback
.
<?php
function add($a, $b) {
return $a + $b;
}
$add = curry('add'); // vrátí instanci CurriedCallback
$inc = $add(1); // taktéž vrátí instanci CurriedCallback, s prvním argument inicializovaným na 1
array_map($inc, array(1, 2, 3, 4, 5)); // === array(2, 3, 4, 5, 6)
- jtousek
- Člen | 951
Panda napsal(a):
jtousek napsal(a):
… přidal třídě Callback metodu use…
use
je klíčové slovo PHP, to bych do toho rozhodně netahal, bylo by to zavádějící. Spíš něco typusetInvokeArguments()
.
jj, zapomněl jsem, samozřejmě by bylo nutné zvolit něco jiného. Ale stále si myslím, že je to nejlepší metoda.
- v6ak
- Člen | 206
Jo, ale pokud to nemá měnit stav, ale jen vytvořit obálku, pak je název
začínající na „set“ poněkud zavádějící.
Jinak obálku jsem navrhoval přesně z tohoto důvodu. Kontrola argumentů je
v obálce poněkud problematická, má-li fungovat na obecný callback. Navíc
asi i zbytečná, protože to tu obstarává PHP, ne? Je to sice trošku leaky
abstraction, ale IMHO je to to méně špatné řešení.