Vyjadřovací schopnosti objektů pro API
Školení, která pořádám
Když chceme v objektu zpřístupnit předem neznámé x
, tak máme vedle tradičního způsobu (definice metody, která bude x
přijímat jako parametr) i řadu dalších možností:
<?php
$obj->x; // definicí metody __get() a příbuzných
$obj->x(); // definicí metody __call()
$obj["x"]; // implementací rozhraní ArrayAccess
$obj("x"); // od PHP 5.3 definicí metody __invoke()
?>
Např. v knihovně SOAP je jistě mnohem pohodlnější volat $soap->search($query)
než $soap->__soapCall("search", array($query))
. SimpleXML toho také obratně využívá a $xml->tag
používá pro přístup k vnořeným značkám, $tag["attr"]
pro přístup k atributům a $tag[0]
pro přístup k jednotlivé značce.
Přemýšleli jste ale někdy o tom, proč to není naopak, proč se nepoužívá $xml["tag"]
a $tag->attr
? Co je přirozenější, nemůže se to plést?
A jak u jiných knihoven? Je lepší $table["column"]
nebo $table->column
nebo by mělo fungovat oboje? A co odkazy na jiné tabulky – je lepší $article["author"]->name
nebo $article->author["name"]
? Nebo snad $article->author->name
? Jak pak ale poznáme, jestli je $article->author
odkaz na cizí záznam nebo samotné ID?
A co závislé záznamy? Bude lepší používat $article->comments()
nebo si vystačíme s $article->comments
a teprve podle pokusu o iteraci poznáme, že má jít o dotaz do jiné tabulky a ne o získání sloupce ze stejné tabulky?
Diskuse
K poslednímu odstavci - určitě nad tím dumáš kvůli Finoqu, který jsi předváděl na PS :) Metoda comments() je nesmysl, nic to nevyjadřuje, je to podstatné jméno v množném čísle. Přístup k property comments je mnohem hezčí. A neměla by za tím být nějaká magie, mělo by to vždy vracet to samé. Pokud má programátor v tabulce sloupec comments a zároveň přes cizí klíče spojenou tabulku comments, tak by si zasloužil nakopat :) (= vyhodit InvalidStateException :o))
Proč by ve sloupci comments nemohl být dopočítaný počet komentářů článku a v tabulce comments potom samotné komentáře?
Nepoužívání sloves pro metody je podle mě hlavní důvod, proč se neujalo jQuery... Vždyť si vemte, co je to za nesmysl - $('a').attr('href').
jája:
tak ono se jQuery neujalo?
btw. myslela jsem, že tento příspěvek bude obsahovat nějakou dobře míněnou radu...
Honza Marek:
U toho jQuery se na to dá rychle zvyknout. Bez parametru je to getter, s parametrem setter. Výhodou je, že je pak kód o hodně kratší. No a říct, že se jQuery neujalo, to bych si fakt nedovolil :-D
LuKo:
Nechci mluvit za Jakuba, ale trpím silným pocitem, že ten Jakubův příspěvek je ironie, čímž by se mnohé vysvětlovalo ;-)
"Nebo snad $article->author->name? Jak pak ale poznáme, jestli je $article->author odkaz na cizí záznam nebo samotné ID?" označovat idčka jako something_id ;) Pak se tohle nemusí řešit a vypadá to nejlíp ;)
Jenže taková knihovna musí být obecná a musí počítat s tím, že ve sloupci comment bude odkaz do tabulky comment a že vedle tabulky comments bude existovat i stejnojmenný sloupec.
pekelník:
$article->comments() - tohle by mohla být tabulka
$article->comments - tohle by měl být určitě sloupeček
$article['comments'] - tohle by taky mohla být tabulka
Mně se více líbí možnost 1)
Mě to takhle taky přijde přirozenější, jedna implementace to tak už dokonce má, ale není divné, že SimpleXML to má v hodně podobné situaci naopak ($xml->tag a $tag["attr"])?
v6ak:
Díky, ale stejně furt nechápu, proč nemohli znovupoužít __call.
Jakub Vrána :
__soapCall přijímá víc parametrů, které by __call v budoucnu mohlo používat pro něco jiného. Podle mě je správně, že to je jiná metoda. Ale __call mimochodem existuje taky.
v6ak:
Pak mi ale nedávají smysl ta dvě podtržítka v soapCall.
Jakub Vrána :
Ta jsou tam právě kvůli schopnosti volat metody přímo. Takže normální metody se volají jejich jménem a PHP metody začínají dvěma podtržítky. Když by se metoda jmenovala soapCall, tak by její název mohl kolidovat se vzdálenou metodou. Takhle může teoreticky kolidovat taky, ale předpokládá se, že vzdálené metody dvěma podtržítky začínat nebudou.
v6ak:
Aha, to pak jo. No, je to takové zvláštní, ale aspoň to už chápu. Díky.
juzna:
ja pouzivam nazvy sloupcu camelCase s malym pocatecnim pismenem, pak:
$clanek->autor - idcko autora = sloupec z DB
$clanek->Autor - zde uz je objekt
$clanek->Autor->jmeno, $clanek->Autor->firma
muzu to pak retezit:
$clanek->Autor->Firma->Adresa->ulice
Trosku horsi je to u zkratek (IP, MAC, DNS), ze sloupce v DB holt musim mit ip, mac, dns...
Jakub Vrána :
Zajímavé. Ale určení chování podle závislosti na velikosti písmen je podle mě ještě horší než podle [] VS ->.
Navíc první velké písmeno používám výhradně pro názvy tříd.
juzna:
Prvni velke pismeno pouzivam pro nazvy trid a tabuky v databazi. Mala pismena pro promenne a sloupecky v DB. Pak to vetsinou pasuje.
$clanek->autor - promenna, sloupec, tedy bude to ID
$clanek->Autor - tabulka Autor, trida Autor, pak je to tedy instance tridy Autor ktera reprezentuje zaznam z tabulky Autor.
Take se mi to nezda jako _spravne_ reseni, ale lepsi jsem nenasel. Hodne me zajima vysledek teto diskuze!
juzna:
libi se mi, jak to ma udelane javascript:
obj->x je ekvivalentni obj['x']
Kdyz predem vim strukturu, muzu psat:
clanek->Autor->jmeno
kdyz mam nejake specialni atributy (co obsahuji treba pomlcku):
clanek['special-id']
a kdyz pristupuji dynamicky tak:
clanek[varName]
Nevim, zda je neco podobneho mozne i v PHP
Jakub Vrána :
V PHP je to možné triviálně, navíc se dá psát i $obj->$var. Mě se tohle taky líbí, na druhou stranu třeba v tom SimpleXML to dělá dvě různé věci a dává mi to smysl.
cucací potřeby:
Existuje na tyto konvence pojmenovávání nějaká ""norma"", best practice nebo doporučený postup?
Diskuse je zrušena z důvodu spamu.