Advanced PHP Trickery

napísal , 22 Jan 2012 [ PHP ]

Viete čo sú v PHPčku anonymné funkcie, closures, ako fungujú statické premenné vo funkciách a načo je register_shutdown_function()? Ak nie, ste na správnom mieste, za 2 minúty to budete vedieť a budú z vás neporaziteľní mágovia PHP. Ak to už viete, môžte sa spokojne potľapkať po chrbte, znamená to, že ste asi s PHP strávili viac času, ako by bolo zdravé :)

Poďme si tieto 4 veci vysvetliť na krátkom príklade "zo života". Predstavte si, že máme triedu na odosielanie SMSiek. Ale predtým než začneme posielať SMSky, sa treba prostredníctvom triedy pripojiť k serveru a po doposielaní všetkých SMS sa treba odhlásiť.

My sa však nechceme zaoberať takými blbinami ako pripájanie a odpájanie. Cheme mať len globálnu funkciu send_sms(). Na to použijeme celkom elegantné riešenie, v ktorom budú obsiahnuté všetky spomínané advanced koncepty.

Statické premenné vo funkciách

function send_sms($number, $text)
{
	static $connection = false;

	if (!$connection)
	{
		require_once('extensions/SMS/connect.php');
		$connection = new SMSConnect();
		if (!$connection->create("login","heslo")) return false;

Statická premenná vo funkcii si zachováva hodnotu v rámci všetkých volaní danej funkcie. Pri prvom spustení bude obsahovať hodnotu false. Podmienka nižšie sa teda vykoná, do premennej $connection strčíme SMSkovú triedu a pripojíme sa k serveru. Pri ďalšom spustení funkcie bude v premennej SMSková trieda a celý tento blok "if" sa preskočí.

V OOP sa zvyknú používať statické premenné vo vnútri tried, každopádne je dobré vedieť, že sa dajú použiť aj vo vnútri funkcií. V manuále nájdete ďalšie príklady využitia.

		$callback = function() use($connection)
		{
			$connection->Logout();
		};

		register_shutdown_function($callback);

Na tomto čudnom kúsku sa nachádzajú zvyšné 3 koncepty. V skratke docielime, že keď dobehne PHP skript, zavolá sa odhlasovacia metóda SMSkovej triedy.

Anonymné funkcie

Prvý koncept sú anonymné funkcie. Čiže funckie bez mena. Ako sa dajú volať funkcie ktoré nemajú meno? Takto:

$gule = function($hodnota) {
	echo "Počet gúľ: $hodnota";
}
$gule(42);
// Počet gúľ: 42

Closures

S anonymnými funkciami súvisia closures (netuším ako sa to povie po slovensky:). Closure je v podstate jav, kedy do anonymnej funkcie magicky prejdú premenné z nadradeného kontextu (scope). Príklad:

$atribut = "Kaliber";

$gule = function($hodnota) use ($atribut) {
	echo "$atribut gúľ: $hodnota";
}
$gule("masívne");
// Kaliber gúľ: masívne

Kľúčové slovo use udáva ktoré premenné majú magicky prejsť z nadradeného kontextu. V takom Javascripte sa closures dejú automaticky, netreba nič špecifikovať. Mimochodom pozor na PHP manuál. Anonymné funkcie sú tam označované ako closures, čo je blbosť! To sú 2 rozdielne veci. Funkcia je funkcia, closure je jav prejdenia premennej do iného kontextu.

register_shutdown_function

No a nakoniec si povieme niečo o register_shutdown_function($funkcia[, $parameter1[, $parameter2[, ...]]]). Čo robí táto funkcia je zrejmé z názvu. Keď dobehne PHP skript, zavolajú sa registrované funkcie (v poradí v akom boli registrované). Ak skript počas behu padne kvôli chybe, nezavolá sa nič.

Keďže prvý parameter je callback, máme viacero možností - môžme použiť názov globálnej funkcie register_shutdown_function('mojaFunkcia'), metódu objektu register_shutdown_function(array($objekt, 'mojaMetoda')), statickú metódu triedy register_shutdown_function(array('MojaTrieda', 'mojaMetoda')) alebo anonymnú funkciu, ako v príklade vyššie register_shutdown_function(function() { echo 'lol'; })

Aby sme dokončili reálny príklad zo života, už len odošleme SMS.

	}

	return $connection->sendSMS($number,$text);
}

Nerozsekaný príklad s SMSkami

Teraz by ste teoreticky mali chápať celý príklad s odosielaním SMSky. Ak nechápete, je možné, že som to na riť vysvetlil. :) V takom prípade napíšte do komentárov a skúsim to uviesť na pravú mieru.

function send_sms($number, $text)
{
	static $connection = false;

	if (!$connection)
	{
		require_once('extensions/SMS/connect.php');
		$connection = new SMSConnect();
		if (!$connection->create("login","heslo")) return false;

		$callback = function() use($connection)
		{
			$connection->Logout();
		};

		register_shutdown_function($callback);
	}

	return $connection->sendSMS($number,$text);
}

send_sms("+421903031337", "Ach ty bzdocha"); // tu sa pripojíme
send_sms("+421903031337", "Stvrtok je a cibulu doma nema");
send_sms("+421903031337", "To je zivot");
send_sms("+421903031337", "MRAVCE CHODA");

// a tu sa odpojíme
napísal , 22 Jan 2012

8 komentárov

komentuj ku každému komentáru sa v databáze ukladá iba meno, text a dátum, iba za účelom zobrazenia pod článkom
neukladá sa email, IP adresa ani informácie o prehliadači a údaje sa nepoužívajú na reklamu, newsletter, na žiadnu ekonomickú aktivitu, nikam sa neposielajú, sú v databáze len aby sa mohli zobraziť pod článkom
  1. johno [ Nedeľa 22.1.2012, 20:13 ]

    Ty vole uz fakt chodte do Ruby. Na toto sa neda pozerat ;)

    Na @rubyslava nedojdes?

  2. 81403 (blade) [ Nedeľa 22.1.2012, 21:48 ]

    Čo sa ti nezdá? :) To už radšej Python, Ruby je pre hipsterov :p
    Každopádne najväčší problém, čo ma odrádza od Ruby a Pythonu, je v hostingoch. Vlastný server nechcem (kto by to nastavoval) a hostingy majú akurát PHP

    Hádam aj hej, už som nad tým viackrát uvažoval, len som sa k tomu stále nejak nedostal

  3. johno [ Nedeľa 22.1.2012, 22:11 ]

    Pride mi to teraz po rokoch uz hrozne ukecana syntax a zbytocne vela klucovych slov a neobjektove...

    Inak co sa stane ked sa ti nepodari poslat sms?

    Hostingy sa riesia furt a nieco take, ze nahram skript a ficim ma snad len heroku. Websupport u nas robi nejake pokusy, ale nie je to zatial ziadna slava.

  4. 81403 (blade) [ Nedeľa 22.1.2012, 22:37 ]

    Heh, že ukecaná syntax. Čo by si potom povedal na Javu? :)

    Keď sa nepodarí poslať SMS, iba bude stále vracať false. V normálnej prevádzke by tam bolo vhodné dať aj prečo sa to nepodarilo a napríklad ak je málo kreditu, poslať mail adminovi.

    Čo používaš ty?

  5. johno [ Pondelok 23.1.2012, 20:19 ]

    Na Javu by som tiez povedal, ze je ukecena, ale kam by som dosiel, keby som sa mal porovnavat vzdy s niecim horsim, ze? ;)

    Ja pouzivam samozrejme Ruby. Prechod z PHP mi teda chvilu trval, ale nelutujem to ani sekundu.

    Ja na podobne veci pouzivam normalne frontu s workerom co bezi mimo aplikacie.

  6. johno [ Pondelok 23.1.2012, 20:52 ]

    Inak tieto notifikacie na mail mi tu este ani raz nedosli ;)

  7. 81403 (blade) [ Streda 25.1.2012, 00:08 ]

    Ale mal som na mysli, či používaš vlastný server?
    Ach jaj, ani sa nečudujem, to sú tie pofidérne WordPress pluginy :)

  8. johno [ Streda 25.1.2012, 13:19 ]

    Presiel som cez shared hosting a rails az po vlastny server. Ono vela ludi sa toho boji, ale ja som s tym problem nikdy nemal, instalacia celeho servera, aby na nom bezalo ruby a potom uz len davas deploy aplikacie jednou komandou trva tak 2hodiny. Potom dalsie aplikacie su uz rychlejsie. Nerobim to tak casto, ze by som to potreboval nejako viac automatizovat. Keby som to robil na dennej baze, tak idem do niecoho ako heroku.

ku každému komentáru sa v databáze ukladá iba meno, text a dátum, iba za účelom zobrazenia pod článkom
neukladá sa email, IP adresa ani informácie o prehliadači a údaje sa nepoužívajú na reklamu, newsletter, na žiadnu ekonomickú aktivitu, nikam sa neposielajú, sú v databáze len aby sa mohli zobraziť pod článkom