Operátor yield

Školení, která pořádám

HipHop for PHP kompiluje PHP kód do C++, čímž podstatně zvyšuje výkonnost. Kromě toho nabízí některé obraty navíc, např. XHP (to se ale dá použít i samostatně).

Nejzásadnější odlišností HipHopu od běžného PHP je nenápadný operátor yield. Ten dovoluje přerušit funkci a při příštím zavolání v ní pokračovat na místě, kde jsme naposledy přestali. Obdobný operátor existuje i v dalších jazycích, např. v Pythonu.

K čemu je něco takového dobré? Představte si, že máme na stránce několik komponent a každá z těchto komponent potřebuje načíst nějaká data (např. z databáze nebo z keše). Lze snadno vypozorovat, že čím méněkrát se s úložištěm komunikuje, tím je celý systém rychlejší. Vyplatilo by se tedy v prvním kroku od každé komponenty zjistit, co potřebuje nejdříve, pak to všechno najednou stáhnout a pokračovat získáváním dat, která jsou na tomto prvním kroku závislá. A přesně k tomu se dá operátor yield použít.

Jak by vypadala funkce pro získání článku, jeho značek a názvů těchto značek?

<?php
function getArticleWithTags($id) {
    $article = yield wait_for(getArticle($id));
    $tags = yield wait_for(getArticleTags($article));
    $article->tagNames = yield wait_for(getTagNames($tags));
    yield result($article);
}
?>

Volající kód obejde jednotlivé komponenty a shromáždí všechno, co potřebují. Pak data jednou komunikací s úložištěm získá a komponentám to zase rozdělí. wait_for() je celkem jednoduchá funkce, která si pamatuje, co všechno se má získat. yield result() je totéž jako return, který nelze ve funkcích s yield používat.

Pokud je vám příklad povědomý z článku o NotORM 2, tak jste ho poznali správně. S využitím operátoru yield se dá aplikace snadno navrhnout tak, aby data načítala odloženě a využila všech výhod s tím spojených (např. jednodušší a efektivnější kešování). Anonymní funkce používané NotORM 2 i operátor yield se tedy dají použít k různým implementacím té stejné myšlenky.

Jakub Vrána, Seznámení s oblastí, 27.2.2012, diskuse: 5 (nové: 0)

Diskuse

NoxArt:

Není trochu problém (s yield nemám zkušenost), že getArticleWithTags vrací po každém volání úplně jiný výstup? Nebo že u několika volání stále nemáme defakto to, co chceme?
Možná jsem to tedy jen nepochopil.

Každopádně viděl bych, že střídmost by tu měla být celkem na místě ... způsob NotORM mi přijde mnohem jasnější, lazy loading tam je a navíc si vždycky explicitně řekneme, co přesně chceme. Poslední yield ve funkci je uložen globálně, že?

Když už, tak bych viděl příklady typu
someFunction{-inicializace-nějakýCyklus{ ... yield }}
při použití ala while( x=someFunction ){} kde by to vracené bylo stále stejné sémantiky (a datového typu) ... to stejné jde tedy zapsat i objektově se všemi benefity OOP. Jen to možná bude o trošku pomalejší

ikona Jakub Vrána OpenID:

getArticleWithTags() nic nevrátí, dokud nezavolá yield result(). Samotné yield znamená „přeruš mě tady, udělej si, co potřebuješ, a pak tady zase pokračuj“.

Toto využití operátoru yield je potřeba srovnávat s NotORM 2, tedy s registrací anonymních funkcí, které se zavolají v momentě, kdy jsou data k dispozici. To mi osobně přijde o dost složitější, i když propojením s Latte se to dá zase o něco zjednodušit.

Nevím, co přesně máš na mysli globálním uložením, ale odpověď na otázku je nejspíš „ne“.

Lazy-loading NotORM s tím moc porovnávat nejde – nestačí, aby se dotazy provedly, až když to je potřeba. Je nutné, aby se provedly všechny najednou, což se nám s NotORM < 2 nikdy nepovede.

Franta:

Z tvého výkladu bych asi nepochopil, jak yield funguje… Tady mi to přijde vysvětlené líp: http://stackoverflow.com/questions/231767/…-keyword-explained

Je to stejný yield, nebo ten tvůj funguje nějak jinak?

ikona Jakub Vrána OpenID:

Ano, je to ten stejný yield a je to tam skutečně lépe vysvětlené. Já jsem místo vysvětlování yieldu na jednoduchém nepraktickém příkladě (z kterého se dá ale jeho chování dobře pochopit) skočil rovnou k jeho využití na něco celkem složitého, ale zároveň velmi užitečného.

Láďa:

Ahoj Jakube,
zkouším tvůj kód rozjet na PHP 7, ale nedaří se mi. Nevím, co by mělo <?php wait_for()?> vracet, aby <?php $article?> nebyl NULL (alespoň předpokládám, že má obsahovat data pro článek).

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.