Proč mám rád PHP

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

Když se mě někdo zeptá, co se mi líbí na PHP, tak obvykle odpovídám „jednoduchost“. Jazyk je poměrně expresivní, ale zase ne moc jako třeba Perl nebo některé preprocesory JavaScriptu.

Jednoduchost

Jak se v PHP projde pole, pokud nás zajímají klíče i hodnoty?

<?php
foreach ($array as $key => $value) {
    // ...
}
?>

V JavaScriptu je to o poznání horší:

for (var key in obj) {
	if (!obj.hasOwnProperty(key)) {
		continue;
	}
	var value = obj[key];
	// ...
}

I když si odmyslím hasOwnProperty (bez kterého se obejdu, pokud se používané knihovny chovají slušně), tak zůstává další problém – když není procházený objekt pěkná krátká proměnná, ale třeba volání funkce, tak si ji nejprve musím uložit do pomocné proměnné. Řada JavaScriptových frameworků proto nabízí helper pro procházení objektů. Už jen fakt, že uživatelská knihovna nabízí pomoc pro tak základní obrat, jako je procházení objektů, je trochu děsivý. Jeho použití je navíc krůček do callback hell:

jQuery.each(obj, function(key, value) {
	// ...
});

Jak vypadá projití asociativního pole v Javě?

import java.util.Map;

for (Map.Entry<String, Object> entry : map.entrySet()) {
    String key = entry.getKey();
    Object value = entry.getValue();
    // ...
}

Kromě čtyřnásobného počtu napsaných znaků mi vadí ještě jedna věc – nutnost naimportovat použitou třídu. To bych musel udělat i v případě, když bych si výsledek map.entrySet() chtěl uložit do pomocné proměnné (třeba pokud bych potřeboval zjistit i velikost). Z dob, kdy v PHP bylo potřeba ručně includovat soubory s třídami, mi zůstal způsob přemýšlení, že pokud používám něco, co už vložený soubor nevyhnutelně musí používat, tak to nemusím vkládat znovu. V Javě ale neříkám, kde se má Map najít, ale která Map se má použít.

Placatost

Tím se dostávám k další věci, která mi na PHP vyhovuje – placatost. Všechno je po ruce, obvykle v globáním jmenném prostoru. Nette mi víc vyhovovalo v době, kdy se Nette\Application\UI\Form jmenoval prostě AppForm. Potřebu jmenných prostorů chápu, ale já bych dal všechno pod jeden jmenný prostor daného projektu. Nechci při psaní kódu přemýšlet, jestli Form zrovna znamená Nette\Application\UI\Form nebo Nette\Forms\Form.

Ukecanost

Když chci v PHP zjistit, jestli řetězec obsahuje regulární výraz, použiji funkci preg_match($re, $string). Když chci zjistit, jestli celý řetězec odpovídá regulárnímu výrazu, přidám stříšku a dolar. V Javě ke stejnému účelu slouží obrat Pattern.compile($re).matcher($string).find() resp. Pattern.compile($re).matcher($string).matches(). Java nabízí i zkratku Pattern.matches($re, $string), pro metodu find ale žádná zkratka neexistuje. Navíc tato zkratka je nevhodná, protože při opakovaném použití se regulární výraz znovu a znovu kompiluje. PHP si naproti tomu zkompilovanou verzi ukládá do keše. Regulárních výrazů je obvykle jen omezený počet a jsou poměrně krátké, takže to ničemu nevadí. V Javě se zkompilovaný regulární výraz obvykle ukládá do konstanty, ale to znemožňuje použití zkratky. Stejně tak metoda String.replaceAll – když pominu nešťastnou existenci metod replace a replaceAll, kde každá dělá něco jiného, tak jde opět o zkratku nevhodnou k používání. To by sakra nemohla metoda replaceAll přijímat i Pattern?

Další ukázkou nepohodlného API v Javě je práce s XML dokumenty. Načtení XML dokumentu z řetězce (tedy obdobu DOMDocument::loadXML) zajišťuje obrat (new DocumentBuilderFactoryImpl()).newDocumentBuilder().parse(new InputSource(new StringReader(html))). Jak se dokument do XML řetězce zase uloží (tedy obdobu DOMDocument::saveXML), snad ani nechcete vědět.

Pokročilé obraty

PHP má pokročilejší obraty (např. rozhraní nebo viditelnost proměnných), které v některých jazycích vůbec nejsou (Python nebo JavaScript) a které přitom dokáží některé myšlenky dobře vyjádřit.

Magie

Řada lidí vyčítá PHP jeho magičnost, mně to ale tak velký problém nepřijde. Přistoupím k vlastnosti objektu, která neexistuje? Třída nejspíš definuje metodu __get. Procházím objektem pomocí foreach? Třída nejspíš implementuje rozhraní Traversable. Přistupuji k prvkům objektu jako by to bylo pole? Nejspíš je implementované rozhraní ArrayAccess. PHP projekty magií obvykle moc prolezlé nejsou a když nějakou použijí, tak mi obvykle nečiní problém ji odhalit a pochopit, o co jde. V Javě s magií zápasím mnohem víc, jedním z důvodů je Guice. Z kódu není patrné, co se vlastně zavolá, dokud neprozkoumám konfiguraci ležící obvykle velmi daleko. A to je ještě to nejmenší – velmi dlouhou dobu jsem strávil nad funkcí, jejíž název se sice nikde v kódu nepoužil a přesto se volala. Proč? Jednoduše vracela typ, který jiná funkce potřebovala, tak ji nějaká magie (ne přímo v Javě, ale v uživatelské knihovně) prostě zavolala. Co by se stalo, když by takové funkce byly dvě? Hádám, že by došlo k chybě. Co když bych ale na dvou různých místech potřeboval zavolat dvě různé funkce vracející stejný typ? Odpověď jsou anotace – typ oanotuji a tím ho udělám unikátní. A tím se dostáváme k další věci, která mi na Javě přijde velmi komplikovaná – anotace, generika a typový systém obecně. Vezměme si třeba tuto signaturu funkce:

public static <T> List<List<T>> partition(List<T> list, int size)

Přijde mi to nepřehledné a strašně dlouhé. Nebo takovýto parametr v deklaraci funkce:

public void f(@DisplayServerUsageProducer.Produce Present<List<DisplayServerUsage>> displayServerUsage)

Anotace sice dovolují stručně vyjádřit některé myšlenky, ale zároveň kód znepřehledňují. Když vidím, jak se anotace používají v Javě, tak jsem nakonec rád, že se do PHP nedostaly.

Čekal bych, že když už je Java tak ukecaná, tak bude sice těžší na psaní, ale jednodušší na čtení. Bohužel to ale nepozoruji – všechny ty informace mi často zatemňují to, co se v kódu opravdu děje.

Jakub Vrána, Osobní, 4.9.2013, diskuse: 103 (nové: 0)

Diskuse

Martin:

osobní preference maji lidé různé. stejně dobře by šlo napsat proč mám rád fortran nebo basic. o kvalitě jazyka to neříká nic.

java i php byly kdysi dobré, ale doba se změnila a je škoda ustrnout jak nějaký dedousek

Jiří Duben:

Opravdu jsou tohle ty pravé důvody? Já spíš na takovou otázku odpovídám "protože mi to sedne", "protože je to kompatibilní s mým mozkem", "protože takhle přemýšlím".

Každý si oblíbí něco jiného a je zajímavé, jak člověk může vyzkoušet nějaký vychvalovaný jazyk a nejde mu v něm psát.

lenochware:

Me se libi jeho primocarost a prakticnost - muzete zacit ihned resit vas problem aniz byste se museli moc zabyvat technikaliemi a omackou kolem.
Dal se mi libi to, ze neni striktne typove - zjednodusuje to programovani i kdyz to muze vest k ruznym zaludnostem.
Sympaticka je i velka knihovna funkci - pokryvajici vetsinu oblasti souvisejicich s vyvojem webu - standardne k dispozici v php.
Myslim, ze duvod uspechu je podobny jako duvod uspechu HTML. Je zajimave, ze se komplikovanejsi koncepty, napr. XML/XHTML, jako nahrada moc neujaly a spis se pridavaji nove vlastnosti pod hlavickou html5.

ikona Lukáš:

No já nevím, ale dokazovat jednoduchost PHP tak, že ho porovnám s nejukecanějším jazykem na světě a s jazykem, který prostě JE zprasený, mi nepřijde zrovna fér. Stačí vzít CoffeeScript nebo C# a už procházení asociativního pole v PHP nijak jednodušeji nevypadá.

ikona Jakub Vrána OpenID:

CoffeeScript má projití pole v pohodě. Na něm mě naopak trochu děsí jeho stručnost. Např. definice funkcí je na můj vkus moc málo ukecaná. Taky rozdíl mezi -> a => se při čtení kódu snadno skryje.

Account = (customer, cart) ->
  @customer = customer
  @cart = cart

  $('.shopping_cart').bind 'click', (event) =>
    @customer.purchase @cart

Lacoz:

Mne to pride dostatocne citatelne, inac necakal by som ze @customer (this.customer) v jquery on callbacku bude nejaka property toho elementu.

Jirka U.:

Za to rozdíl mezi if($a = 'a') a if($a == 'a') je přehlédnutelný :)

ikona Jakub Vrána OpenID:

To je samozřejmě taky špatně. Lépe by mi vyhovovalo, když by to bylo potřeba psát aspoň jako if (($a = 'a')).

cabadaj:

"Např. definice funkcí je na můj vkus moc málo ukecaná." Tak co vlastne chces, strucnost (je nutno se naucit vnimat kazdy znak) nebo ukecanost. Me napriklad Coffeescript prijde OK. Cela tahle diskuze a ji podobne jsou trochu divne. Je to vetsinou spis o pocitu. Kazdy jazyk ma svoje vyhody a nevyhody a zalezi co ti jak sedne. A hlavne se kazdy hodni na neco jineho. Dulezite je, aby se navzajem inspirovaly v dalsim rozsirovani.

ikona Jakub Vrána OpenID:

Chci něco tak akorát. Ani ne moc ukecané (jako třeba Java), ani ne moc hutné (jako třeba Perl).

76house:

A co trochu rovnocennější srovnání? Třeba s ruby nebo pythonem?

ikona Jakub Vrána OpenID:

Python je v článku zmíněn pro nedostatek pokročilejších obratů. Na druhou stranu má několik pokročilých obratů, bez kterých bych se radši obešel, např. metaclassy nebo deskriptory.

loki:

1. pokial viem tak python ma multiple inheritance takze interfaces nepotrebuje.

2. viditelnost clenov sa v pythone riesi pomocov prefixov. members zacinajuce prefixom __ sa zvonku nedaju zavolat.

ikona Jakub Vrána OpenID:


1. Dědičnost vyjadřuje vztah „je“, rozhraní vztah „umí“. Říkat, že objekty nemusí něco „umět“, protože „jsou“ více věcmi najednou, svědčí o špatném uvažování.

2. Vím, že tahle konvence existuje. Ale jednak se mi nelíbí a jednak se dá snadno obejít. „private $a“ je čitelnější než „self.__a“.

v6ak:

1. Proti multiple inheritance existují různé oprávněné námitky (ehm, diamond...), ale toto bych tomu nevyčítal. Když něco jsem, tak evidentně něco umím. Bez toho by nefungoval ani polymorfismus bez interfaces.

2. Taky se mi to nelíbí (Co když chci změnit viditelnost?), ale možnost to snadno obejít - pokud to člověk nemůže udělat snadno omylem, IMHO to až tak nevadí. Úmyslně ale lze dělat někdy dost divné věci, že si člověk nebude jist, že 1+1=2: https://gist.github.com/v6ak/988502

starenka:

Co myslíš pokročilejma výrazama, který v Pythonu chybí?

ikona Jakub Vrána OpenID:

Třeba viditelnost proměnných nebo typehinting.

starenka:

Ano to nejsou. Otazka je, jesli to je treba a jestli je to "pokrocilej obrat". Navic ty veci spolu tak nejak souvisi. Souvisi s kulturou psani kodu v Pythonu.

Clovek tak nejak predpoklada, ze sme tady vsichni dospely, cili kdyz vidi obj._foo nebo obj.__bar musi mu bejt jasny, ze mu tim nekdo naznacuje, ze pokud se do nich bude hrabat, tak by mel vedet, co dela. To, ze to jde cist/prepisovat jde neberu jako nevyhodu.

Pokud pises poctive dostringy, muzes se v nekterejch IDE typhintingu dockat, docka se ti z nich taky vygeneruje.
Osobne si ale myslim, ze je hlavni veci dobre pojmenovat a potom zadnej typehinting neni treba.

Na druhou stranu se php (tedy pokud vim, nejak to nesladuju) muze zdat o vecech jako jsou dekorator, metaklasa, generat, list/dict comprehensna, nejaky normalni slicovani iterablu, context manager apod.

Nicmene clanek je o eleganci a tu bych tedy php rozhodne nepripisoval.

ikona Jakub Vrána OpenID:

Kontrola typů předávaných hodnot mi poskytuje velký klid na duši. Vygenerovaná dokumentace není tak důležitá. Důležité je, že když mi někdo předá typ, který nečekám, tak mi to jazyk dá nahlas vědět a ve funkci ani v aplikaci to už nemusím speciálně ošetřovat.

Metaclassy a některé další pokročilé obraty Pythonu považuji za překomplikované a jazyku spíše škodící. Jak už jsem psal, tak je pro mě velká úleva, že se v Google nesmí používat.

starenka:

Ok, preskocim-li metaclass, kterou zrejme nemas rad, tak mi pak vyjde, ze kod znepreheldnujou tyhle veci:

- dekoratory

@login_required
def some_view(request):
   pass

- list/dict comprehension

foos = [foo for foo in bars if foo]
swaped = {val:key for key, val in hash.items()}

- generator

def foos():
    for foo in bars:
    if foo:
          yield foo

foos = (foo for foo in bars if foo)

- context managery

with patch.object(Foo, 'bar') as mock_method:
    mock_method.side_effect = ApiError('O HAI')

- slicing iterablu

    'string'[1:5]
        array[:-5]

Asi jsem divnej, ale me prijde, ze to prave docela pridava na citelnosti

ikona Jakub Vrána OpenID:

V Google je zakázané třeba ještě použití dynamic inheritance. Mě se nelíbí třeba ještě existence metod __get__, __getattr__, __getattribute__. Nelíbí se mi ani vícenásobná dědičnost.

Martin:

Tak trochu jsem cekal flame a uz se tu rodi.

to 76house
A nenapadlo te ze autor porovnava jen s tim s cim ma vetsi zkusenosti?

Ja osobne PHP beru, kdyz se v nem pise poradne tak se s nim da krasne pracovat. Sice nejvic pracuju v Jave a soukrome v PHP a zase se chystam na C++, ale kazdy druh projektu vyzaduje urcite vlastnosti jazyka takze ZADNY NEJLEPSI jazyk neni.

v6ak:

Koukám, že asi nepoužíváš moc IDE:
* Já taky moc neřeším, kde najdu v Nette Form. Napířu třeba Form (ani to nemusím napsat celé), zkontroluju, že první vybraný je OK a potvrdím.
* To, že se v Javě musí importovat java.util.Map je to poslední, co by mi tam vadilo - to za mě udělá IDE.
* Ukecanost Javy je v některých případech cena za dobré napovídání. Ano, jde to i levněji (např. type inference), to je ale druhá věc. A jsou jazyky, které nabízejí zhruba stejně kvalitní napovídání v IDE za mnohem nižší cenu. Takže do jisté míry souhlas.
* A tam, kde to není cena za dobré napovídání, pomůže někdy IDE. Nepovažuju to za optimální, ale není to zdaleka tak strašné: http://blog.v6ak.com/2013/01/grahamuv-problem…-ukecany-vadi.html

Anotace - to je otázka, ale souhlasím, že je to někdy trochu magie. Často taky dám přednost jiným řešením. Ale když už anotace (např. v Doctrine nebo v Nette), tak je zase lepší je mít přímo v jazyku.

K funkci, jejíž název se nikde nepoužil, ale přece se volala: Ta prostě byla volána z jiného kódu, který byl ve statickém inicializátoru. Ale totéž se může stát v PHP, pokud bude v souboru s načtenou třídou ještě nějaký jiný kód. Jediný podstatný rozdíl je v tom, že v PHP by se ta třída nenačetla jen kvůli návratovému typu, ale až později.

"Co by se stalo, když by takové funkce byly dvě? Hádám, že by došlo k chybě."
Proč by mělo dojít k chybě? Prostě by se zavolaly obě funkce.

"Co když bych ale na dvou různých místech potřeboval zavolat dvě různé funkce vracející stejný typ? Odpověď jsou anotace – typ oanotuji a tím ho udělám unikátní."
Přiznám se, že tady asi mluvíme o úplně jiné Javě. Naprosto nechápu, proč tu používat anotace, které mimochodem neudělají žádný typ unikátním. Ale hlavně: v Javě nejsou funkce identifikovány podle návratového typu, ale podle názvu metody (a třídy) a vstupních parametrů, takže vážně nechápu, kde je problém.

ikona Jakub Vrána OpenID:

Je pravda, že IDE může leccos usnadnit. Bohužel to, které používám v Google, v této oblasti moc nepomáhá. Moc jiných alternativ ale nemám, protože jednak s tak obřím repozitářem nedokáže většina běžných IDE pracovat a jednak ono IDE nabízí spoustu usnadnění v oblastech, které jsou pro Google specifické (např. code reviews).

Situace s anotacemi se v Javě podle mě zvrhla proto, že jsou first-class citizens. V PHP jsou na okraji společnosti, takže je lidi obvykle použijí, jen když to dává velmi dobrý smysl. V Javě je použijí se stejnou lehkostí jako definují třídu i v situacích, kde se to podle mě moc nehodí.

S funkcemi, jejichž název se nikde nepoužije, se mi to asi nepovedlo vysvětlit moc dobře. Mluvím o systému podobnému Guice (kde mapuji, které třídy mají uspokojit požadavky na které interface). Jde o systém, ve kterém jen zaregistruji nějakou třídu a všechny oanotované viditelné metody uspokojují požadavky všech oanotovaných parametrů metod, které se mají zavolat. Takže pokud by dvě metody vracely totéž, tak by systém nevěděl, kterou z nich zavolat.

Asi by se něco podobného dalo udělat i v PHP, ale nikoho to zatím nenapadlo možná i proto, že anotace nejsou součástí jazyka.

lopata:

Guice je DI Framework, jeden z mnoha v Javě, stejně jako jich je mnoho v PHP, použití anotací u DI frameworku je také běžné jak v Javě, tak v PHP

v6ak:

Asi už rozumím mnohem líp. IDE je zde specifický problém u Google. Myslel jsem, že pro Javu není potřeba příliš vybírat IDE, protože jsem neviděl špatné Javové IDE. (Jsem IDEA-lista, ale byl bych schopen pro Javu používat i Eclipse nebo NetBeans. U PHP nic takového říct nemůžu.)

Uznávám, že se někde anotace v Javě asi nadužívají, ale zatím jsem měl asi celkem štěstí na knihovny a moc jsem se s tím nesetkal. Ale to, že jsou first class citizen považuji za výhodu. Nemyslím teď ani tak @Override (to je fajn, ale nemusí to být nutně anotace), ale třeba problémy v PHP, když se míchají dva různé anotační systémy, kde se každý chová jinak. S tím jsem si užil: https://github.com/Venne/cms-module/issues/10

Jinak je obecně fakt, že vlastnosti jazyka ovlivňují kulturu a že někdy méně může znamenat více. V PHP zase máme například asociativní pole skoro na vše. Když se překlepnu v názvu klíče, je to mnohdy ignorováno.

Jirka Kosek:

Že by Jakub používal to tajné IDE běžící v prohlížeči?

ikona Jakub Vrána OpenID:

Ještě k tomu Form: Nejde jen o to, jak snadno se to napíše, ale i jak snadno se to přečte. Když někde v kódu vidím Form (třeba v typehintu), tak musím přemýšlet nebo dohledávat, o jaký Form vlastně jde. Když vidím AppForm, tak přemýšlet nemusím a nemůžu se splést.

Jan33:

Za mě fail. Pište Jakube prosím o tom co umíte, výpady na jiné nechte spát. Díky.

Franta:

Článek mi přijde jen jako provokace a snaha o flame.

Ale kdyby to přeci jen bylo míněno vážně, mám otázku k:

„public static <T> List<List<T>> partition(List<T> list, int size)
Přijde mi to nepřehledné a strašně dlouhé.“

Když vypustíš informaci o datových typech, k čemu to bude dobré? Jak poznáš, co můžeš poslat na vstup a co máš očekávat na výstupu?

v6ak:

Tak šlo by to i přehledněji (ve vhodném jazyce):

def partition[T](list: Seq[T], size: Int): Seq[Seq[T]]

A dokonce i stručněji (nedoporučuje se pro veřejně API):

def partition[T](list: Seq[T], size: Int)

Souhlasím, že po dalším zestručnění se stejně ty chybějící informace musí přenést někam jinam (např. do dokumentace) a ve výsledku podobný zápis nic neušetří:

def partition(list, size)

A jinak Jakub zde neukázal ukecanost Javy "v plné kráse", kdy musím pro úplnost místo <T> psát něco jako <? extends T>. Při troše zanořování to začne být nepřehledné. Přitom stačí mít immutable collections a v nich povolit vhodnou varianci.

ikona Jakub Vrána OpenID:

Otazníky jsem chtěl zmínit, to je pravda. Díky za doplnění.

ivan:

...obvykle v globáním jmenném prostoru...
A tam to všichni mají, ať o to stojí nebo ne. Aby se s tím dalo přežít, tak se v podstatě povolily backslashe ve jménech tříd a nějaké to aliasování na úrovni souboru a říká se tomu vznešeně jmenné prostory. A aby toho nebylo málo, má PHP ještě superglobál, heč. (No jo, přece slušní programátoři nedělají ošklivé věci).

...PHP má pokročilejší obraty (např. rozhraní nebo viditelnost proměnných), které v některých jazycích vůbec nejsou...
PHP má "skoro všechno" - jako dort od pejska a kočičky. Viditelnost jde obejít (jen s větší námahou). K rozhraní: bez kompilace jsou stejně potřeba testy. (No jo, musíme nějak programátorům zabránit dělat ošklivé věci).

Kde se to hodí, srovnává se s javascriptem, kde se to hodí jinak srovnává se s javou a jinde pythonem. PHP má své výhody (nejpodstatnější je asi rozšířenost), ale vyzdvihovat jeho jazykové schopnosti, to jde jenom takto povytrhávané z kontextu.

ikona Jakub Vrána OpenID:

Souhlasím, že PHP má řadu obratů, na které by bylo lepší zapomenout, superglobální proměnné jsou jednou z nich. Nicméně není tak velký problém se jim vyhnout. Když to člověk udělá, tak může vzniknout kód, který je snadné jak přečíst, tak zapsat, a nejde v něm tak snadno přehlídnout chybu (čímž trpí jazyky s větší expresivitou jako Perl nebo CoffeeScript). Když porovnám třeba kód Phabricatoru s prakticky čímkoliv, co jsem viděl poslední dobou zapsané v Pythonu, Javě nebo JavaScriptu, tak cítím velkou úlevu.

Z mého pohledu se PHP podařilo vyvážit, jak snadné je kód zapsat (snadnější než v Javě, pracnější než v CoffeeScriptu) a především přečíst – z mého pohledu líp, než cokoliv ostatního. Přitom jsem čekal, že Java bude sice pracnější na zápis, ale snadnější na čtení – že mi všechny ty dodatečné informace poskytnou kontext, který mi pomůže kód pochopit. Bohužel mi spíš překáží.

Povytrhávané z kontextu je to schválně. Na většině jazyků mi něco trhá žíly. V JavaScriptu třeba maličkosti typu, že za posledním prvkem objektu se nedá napsat čárka nebo že středník na konci příkazu je volitelný. V Javě mi trhá žíly nadužívání anotací, které vede k nadměrné magičnosti. V Pythonu mi trhají žíly překomplikované obraty typu metaclass. V PHP mi netrhá žíly nic. Sice by se taky dala najít spousta věcí, které mi v PHP vadí, ty se ale naštěstí v projektech, kolem kterých se motám, prakticky nepoužívají.

ivan:

Ty superglobály jsou jen bonus. On ten globální jmený prostor tříd je docela pochybná věc. Mějme knihovnu L ve dvou verzích L1 a L2. A mějme dvě aplikace A1 a A2, kde A1 užívá L1 a A2 užívá L2. A vyvíjejme modul M, který by rád použil nějakou verzi L a měl by být použitelný v A1 a A2. To se dočkáme Fatal error: Cannot redeclare class L\Some in ...

Pabricator neznám, a nikdo netvrdí, že nemůže být kód v php zapsaný lépe než v pythonu, javě nebo javascriptu. To přeci záleží na konkrétním vývojáři. Srovnání zprasený kód v jednom jazyce a promyšlený kód v druhém jazyce toho o jazyku moc nevypovídá.

  Nepovinné středníky v javascriptu jsou samozřejmě nepříjemné. Možnost zapsat čárku za čímkoliv posledním, co se jinak oděluje čárkami vadí i mně (třeba poslední argument volání funkce v php). Nadužívání anotací - jak jsem psal, je věcí daného programátora - to, že jsou v php na okraji společnosti není dobrou stránkou php. Podobně metaclass v pythonu - jestliže to někdo používá tam, kde by to bylo vhodnější řešit jinak, je to o programátorovi, ale ten koncept určitě není sám o sobě špatný.

Povytrhávání z kontextu smíchání nesourodých věcí mi přijde takové "phpčkovské". Na jedné straně článek uvádí, jak je na pytel překomplikovaná signatura javy. Na druhou stranu se vyčítá javascriptu a pythonu, že nemají rozhraní. A přitom rozhraní php např. nedefinuje návratovou hodnotu - takže taková "ochrana napůl".

A php má další radosti "napůl". Do funkce můžeš napsat libovolné parametry navíc, ale v overridlé metodě si další nepovinný parametr nepřidefinuješ (a kouzlíš s func_, mimochodem proti php má python o moooc příjmnějsí práci s parametry). "Jakože funkci" si můžeš uložit do proměnné a zavolat, ale do proměnné třídy ne. Dynamický atribut třídy deklarovat nemusíš, statický musíš. Třídu a funkci do jmeného prostoru uzavřeš, proměnnou ne. A to jsou jen ty "schizofrenní" věci.

Opravdu moc nechápu, za jakým účelem byl článek takto napsán. Kdo zná php a některý ze srovnávaných jazyků ten asi ví, že ve skutečnosti php neční tak, jak je snaha vykreslit. Pro začátečníky může být stejně zavádějící jako mnohé tutoriály stylu echo $_POST; die(); /*uprostred vypoctu ceny*/. No a "only php forever" - ti už si přece svůj nejlepší jazyk dávno našli.

ikona Jakub Vrána OpenID:

Co máš na mysli obratem „jakože funkci nemůžeš uložit do proměnné třídy“?

Článek jsem napsal proto, že mi tato myšlenka hlodala v mozku, podobně jako drtivou většinu ostatních článků na blogu. Z mého pohledu je PHP zkrátka ve většině případů snadnější na čtení, ne příliš složité na psaní a možnost udělat chybu bývá menší. Věci, které se PHP často vyčítají, ve srovnání s tímhle považuji vesměs za malicherné.

ivan:

"jakože funkci nemůžeš uložit do proměnné třídy".
Tím jsem myslel toto:
Php má funkce "function". Pak má ještě něco jako anonymní funkce (opět uvozené "function"), které jsou ale něco jiného (objekty) než původní fuknce. S tím lze pracovat takto:

$a = function(){print 'a';};
$a();

ale nikoliv takto:

class A{
  function test(){
    $this->a = function(){
       print 'Hello';
    };
    $this->a();
  }
}
$a = new A;
$a->test();
#Fatal error: Call to undefined method A::a() in ...

Jak tak čtu diskuzi (i okolo), vidím, že máme jiná východiska. Co mi na php vadí (že má bez ladu a skladu naplácané nedotažené featury, které spolu často neladí), ty bereš jako výhodu, že si z každého přístupu vzalo co se hodilo. Z toho úhlu pohledu máš možná pravdu - php by mělo vycházet líp: pokud začneš od vyzobaných vlastností php a poukazuješ na jazyky, které daný rys nemají nebo mají dotažený (s tím, že to má i cenu, která se za to platí).

v6ak:

Uložíš. Jen se pak hůř volá.

Určitě je to mínus pro PHP, ale jiné, než píšeš.

ivan:

Ok, chyba, uložím, ale ... no, měl jsem to napsat takto:
class B {
  static function test($a){
    $a->test();
  }
  static function test2($a){
    $fn = $a->test;
    $fn();
  }
}
class A{}
class C{
  function test(){
    print 'OK';
  }
}

$a = new A;
$a->test = function(){print 'Hello';};
B::test(new C);
B::test($a); #chyba

B::test2($a);
B::test2(new C); #chyba

Petr Konůpek:

A proč ne třeba Ruby? :)

ikona Jakub Vrána OpenID:

Od Ruby mě odradil tento článek: http://phpfashion.com/ruby-on-rails-dekuji-nechci.

Martin:

Postavit svůj odpor k Ruby na tomhle Grudlově nesmyslném výblitku? To je docela škoda.

v6ak:

Když myslíš, že ten článek je výblitek, dokaž to!

johno:

Jadro kritiky stoji na tomto: "Vylepšují chování celé řady standardních tříd, jako je String, Array, Hash, Date, Symbol, atd…

Jejich úmysly jsou dobré. Ale… Nechám na vaší představivosti domyslet, jak zákeřné chyby mohou vznikat, jak těžko se odhalují, obzvlášť tehdy, pokud se modifikující kód vykoná podmíněně, tedy jen občas. A co teprve, když budete chtít v jedné aplikaci použít dvě knihovny, z nichž každá si prostředí (tj. vestavěné třídy) změní po svém.

Ne, Ruby v tomto ohledu není dobrý jazyk."

1) Je na programatorovi ci taku kniznicu pouzije.
2) Je to hypoteticky problem, ktory sa nepreukazal ako realny. Rails (nie nutne Ruby, konkretne ActiveSupport), ktore toto masivne vyuzivaju su tu uz od roku 2006 a nezaznamenal som ziadny takyto problem. V mojej praxi (5+ rokov) toto nikdy problem nebol. Nikdy.

Odporucam taktiez pozriet na smalltalk a vec co volaju protokoly (zoznamy metod). Je to velmi podobne a presne toto je ucel otvorenych tried. Ak to niekto pouziva zle tak...

"With great power comes great responsibility."

Ruby sa daju vytknut vseliake veci, ale to o com pise clanok je teoreticky vymysel, ktory sice znie dobre je logicky a dokonca s nim aj suhlasim, ale v praxi sa to neukazal ako realny problem. Naopak, realne vyhody prevazuju teoreticke problemy.

ikona David Grudl OpenID:

Johno, že problém nebude v případě RoR reálný, naznačuje konec článku. Je to dáno pozicí hegemona RoR. Naopak třeba v JavaScriptu se jako reálný ukázal, zejména poté, co se programátoři spálili saháním do host objektů (což je, pravda, trochu jiný případ, pro zájemce http://perfectionkills.com/whats-wrong-with-extending-the-dom/)

Jinak článek je 6 let starý a hodně poplatný době vzniku, kdy se o Ruby a RoR psalo pouze a jen v superlativech. Dnes bych ho napsal takto http://phpfashion.com/objevi-rails-dependency-injection.

johno:

Ano, cital som ten tvoj clanok. Mas pravdu, avsak tieto hlasy su v Rails/Ruby komunite uz dlho, zatial vsak vyhrava DHH s jeho niekedy az brutalnym pragmatizmom. To staticke peklo (ako to volas) je do velkej miery dane tym, ze testovanie v Rails je presne na toto pripravene. Cize to vobec vyvojara neboli (aj ked testy su pomale). Nehovorim, ze s tym suhlasim, skor sa mi paci takyto pristup http://victorsavkin.com/post/42542190528/…-developers ale aj to ma svoje uskalia.

Ano automaticke DI ako je v Nette zatial nemame, ale z toho co som videl to je to pre mna skor nice-to-have ako must-have ficura.

Tvrdit, ze DI Ruby nepotrebuje je nezmysel. A velmi rad sa s hocikym pobavim o naozajstnych vyhodach Ruby.

v6ak:

Možná to u Ruby nebude až tak často se objevující problém. Ale po tom, na čem všem jsem se již spálil, bych moc nechtěl v něčem takovém programovat, případně bych si vybíral hlavně knihovny, které toto nedělají.

Jakkoli beru nmitku, že se to zas tak často v Ruby nestává, je to IMHO málo na to, aby to z článku udělalo 'nesmyslný výblitek'.

johno:

Pozor, to ze to je nezmyselny vyblitok som ja netvrdil. Ja s tym clanok do istej miery aj suhlasim, ale to by som sa uz opakoval.

"Ale po tom, na čem všem jsem se již spálil, bych moc nechtěl v něčem takovém programovat, případně bych si vybíral hlavně knihovny, které toto nedělají."

Smiem vediet na com si sa teda v Ruby spalil? A ako to suvisi so spravnym pouzitim otvorenych tried a teda "open for extension, closed for modification?"

v6ak:

"to ze to je nezmyselny vyblitok som ja netvrdil"

Jasný, rozumíme si.

"Smiem vediet na com si sa teda v Ruby spalil? A ako to suvisi so spravnym pouzitim otvorenych tried a teda \"open for extension, closed for modification?\""

Asi jsem se nevhodně vyjádřil, nemyslím tím konkrétně, že jsem se spálil na Ruby ani na monkey patchingu. U tohoto jsme se shodli, že to může (aspoň teoreticky) dělat problémy. Je to přinejmenším srovnatelný problém s nepoužíváním jmenných prostorů. Jenže tady to neskončí okamžitou chybou, ale může si to přinést záhadné chování. Jenže já jsem se už spálil i na mnohem nevinněji vypadajících věcech.

Třeba parametr action je v Nette vyhrazený pro účely frameworku. Jenže když jsem chtěl propojit cizí kód (ne na Nette) s webem v Nette, dost krutě jsem na to narazil. Objem práce se zněkolikanásobil. Jsem navíc obzvlášť háklivý na chyby, kde na první pohled vše projde, ale něco nefunguje tak, jak má. Což je tento případ a může být i případ monkey patchingu.

Navíc problém může být dost mimo můj kód. Třeba jsme se tu kousek vedle bavili o metodě each, u které není úplně jasné pořadí parametrů funkce, kterou volá. Dejme tomu, že někdo vymyslí nějakou novou higher order funkci, která v Ruby není. Druhý udělá totéž, ale zvolí opačné pořadí parametrů. Ani jednu funkci nebudu používat přímo já, ale bude je používat nějaká knihovna, kterou používám já. V závislosti na něčem se mohou obě knihovny načítat v jiném pořadí. A teď ať někdo z popisu zmateného chování programu zjistí, co se vlastně vůbec děje. (A to neřeším, jak problém vyřešit, jen jak ho najít.)

Vím, nikdy si nemohu být 100% jist, že se vyhnu takovým magickým překvapením, ale s tím, jaké na ně mám "štěstí", nechci chodit nebezpečně blízko možných problémů.

johno:

Myslim, ze sa tocime v kruhu, zatial co ty hladas hypoteticke problemy a preto to nepouzivas, ja to pouzivam a uzivam si vyhod, ktore mi to prinasa. Nic z toho co popisujes nie je realny problem. Ak sa bojis, tvoja volba, ale z mojho pohladu iracionalna.

Argument velkym projektom, ktory spomina Vrana nie je realisticky. Rails sam o sebe je obrovsky projekt, ma stovky vyvojarov, bol by prvy na rade keby sa to malo ukazat ako realna hrozba. Vyvoj bezi od roku 2006 a nic sa nestalo. Ano vela magie skodi a v Ruby komunite su bordelari tak ako vsade inde.

Nezabudajte vsak na dolezity fakt, ludia co robia Ruby/Python uz maju vacsinou PHP preskakane (aspon v nasich koncinach). Ukazte mi cloveka co sa dobrovolne vratil od Ruby/Python naspat k PHP. P

S. Dereka Siversa si ale predtym naozaj poriadne pregooglite, aby to nebola mala domov.

ikona David Grudl OpenID:

Takových lidí jsou mraky, běžně je potkávám. Ono to není ani tak vracení se, jako spíš využívání znalosti více jazyků.

v6ak:

Rozumím. Ale jak říkám, na to, že "toto se mi nikde nevymstí" jsem se spoléhal už tolikrát a tolikrát se mi to vymstilo.

Ale do Ruby nejspíš nepůjdu tak jako tak. Projekty, na kterých dělám, bych rozdělil do dvou kategorií:

a) Použij něco, co bude znát ledaskdo. Tady padá volba často na PHP. Člověk může mít proti PHP různé námitky, rozhodně to není ideální jazyk, ale umí to "každý blbec". A zákazník má celkem jistotu, že když odejdu, tak celkem snadno najde někoho jiného. Pro mě je to ale vlastně jediný důvod, pro používat PHP.

b) Použij si co chceš. To mohou být buď moje projekty nebo projekty zákazníků, které jsou brány spíše jako jednorázovky. Nebo zákazník věří, že se se mnou na případné pozdější úpravě dohodne. Ani tady nevolím Ruby a najdou se i jiné důvody než Monkey patching. Buď jde o něco triviálního, na co se hodí bash, nebo ne, a většinou zvolím jazyk Scala. Líbí se mi ve srovnání s Ruby například statické typování (v mnohem příjemnější podobě než u Javy) nebo implicitní konverze. (Implicitní konverze se mimochodem používají dost jako extension method - nahradí monkey patching méně magickým způsobem. Vše se řeší při kompilaci. Metody jsou "přidané" jen pro nějaký úsek kódu, mnoho magie tím odpadá. Nejednoznačnosti se projeví hned při kompilaci.)

johno:

S a) uplne suhlasim, s tym, ze to vidim aj ako nevyhodu PHP. V nasich koncinach ked niekto robi Ruby tak ho mozes zobrat lebo je na 90% vyborny vyvojar, PHP robi kazdy. Ale tym ze Rails sa dostava do mainstreamu, tak sa to postupne meni.

Ad b) ano right tool for the job. Suhlas.

v6ak:

Jasný, je to dvousečná zbraň. Ale pokud má někdo přebírat kód po mě (resp. pokud chci dát zákazníkovi aspoň trochu "záruku", že to snadno půjde), je to prostě výhoda.

A že to může být i nevýhoda, jsem celkem viděl včera, kdy jsem dostal nabídku, že bych udělal malou úpravu formuláře. Žádný framework, spoléhání se na magic_quotes_gpc a další věci mě od toho docela odradily.

ikona Jakub Vrána OpenID:

Ukazuji sebe. Od Pythonu (ve kterém jsem dělal více než rok) jsem se vrátil k PHP.

johno:

A dovod? Lebo ja ti mozem ukazat na kazdeho takeho snad 20 ludi co sa spat nevratilo.

bene:

Treba ja

Vratil jsem se od Ruby k PHP. Sice to bylo z duvodu, ze bylo potreba resit nejaky PHP projekt, ale byl jsem tomu rad a nechtel jsem se vratit zpet k Ruby.

Ruby je krasny jazyk a dava velkou volnost, takovou, ze nekdo pise zavorky nekdo ne. Kdyz dela na projektu vice lidi je to problem, hlavne proto ze se Rubyste (alespon se kteryma jsem se setkal ja) jsou velmi individualni a nechteji se teto individuality vzdat. Delat pak nejake firemni konvence je v pekle.

Taky mam zkusenost, ze se se nekteri Rubyste docela povysovali a bylo mi mezi nimi neprijemne.

Posledni a asi nejvetsi duvod meho rozhodnuti byla komunita v CR. O Ruby se mluvilo jako o zazraku, ktery vse nahradi. Nestalo se tak. Co znam par Rubystu, tak se jejich rady nijak neroszirili a PHP z komercniho hlediska jasne vede. Alespon co se CR tyce.

johno:

Konecne nieco k veci! Diky za komentar.

ikona Jakub Vrána OpenID:

U velkých projektů, kde pracuješ s kódem po stovkách jiných vývojářů, se bohužel vždycky najde někdo, kdo onu „great responsibility“ neměl. Jazyky, které umožňují velké divočiny (jako v některých směrech Python nebo Ruby), dokáží kód velmi znepřehlednit.

Např. Google zakazuje v Pythonu používání metaclass. Je to zkrátka příliš mocná konstrukce, která sice může kód jakoby udělat elegantnější, ale přitom ho zatemní. Když přijdu k cizímu kódu, tak mu chci ihned rozumět, bez studování širokého okolí (jako např. co v Javě dělá která anotace).

ivan:

nejen ruby má zákeřnosti zmiňované v článku:

#A.php
<?php
namespace A;
function
ucfirst(){
  return return
'Tůdle nůdle';
}

#B.php
<?php
namespace A;

include
'A.php';

print
ucfirst("citron");

v6ak:

Dobrý poznámka, ale rozměrů u Ruby to zdaleka nedosahuje:
1. Dá se tomu celkem dobře bránit backslashem na začátku.
2. Netýká se to metod.
3. A hlavně: Funkce ucfirst musí být ve stejném jmenném prostoru, jinak to nemá ten účinek. Tím odpadá velká část magie. Těžko mi to udělá knihovna třetí strany, těžko se takto poperou dvě knihovny různých autorů.

Hlavně díky bodu 3 se tento problém stane snad jen tehdy, když se o to někdo vyloženě snaží. Nedovedu si představit scénář, kdy to někdo udělá omylem, pokud neleze co cizího jmenného prostoru.

johno:

Apropo krasa foreach ($array as $key => $value) { ... }

Ked sa nad tym clovek zamysli, tak to sice je celkom kratke, aj ked v porovnani s Ruby

array.each {|key, value| ... }

je to asi stale dlhe.

Co mi vsak na tomto priklade vadi je, ze foreach je len dalsi konstrukt jazyka, ktory sice vyzera elegatne, ale je uplne prvoplanovy a nepouziva sa na nic ine. Naproti tomu .each v ruby je uplne bezna metoda s blokom ako parameter. Toto su dva konstrukty jazyka, ktore su radovo silnejsie. Mozem vytvarat vlastne metody, ktore beru blok, blok moze mat viac parametrov, metoda moze mat parametre ...

Ano k homoikonicite LISPu to ma este daleko, ale je to ovela elegantnejsie ako rozsirovat gramatiku prvoplanovo konstruktami typu foreach, for, ...

v6ak:

Těch pár znaků je celkem jedno.

A jestli to má být fíčura jazyka, nebo higher order funkce, to je dost otázka. Ano, HOF má své kouzlo a je fajn, když to jazyk podporuje. Používám jazyk, kde si mohu vybrat. A nejsem si úplně jist, jestli je přehlednější list foreach {item => ... }, nebo for(item <- list){...}. Oba zápisy mají jistá specifika (v případě použití pokročilejších fíčur; to je ale nad rozsah tohoto komentáře), ale v jednoduché podobě mi přijde přehlednější ten druhý. Aspoň v této imperativní podobě. U funkcionálních záležitostí mi to tak jednoznačné nepřijde.

Na druhou stranu, pokud chceme jednoduchý zápis a nechceme používat fíčur jazyka, mohli bychom mít třeba each(list){item => ...}.

ikona Jakub Vrána OpenID:

Prvoplánové konstrukce mají výhodu právě v tom, že mají jasně definované, snadno pochopitelné chování a nepoužívají se na nic jiného.

Já moc dobře vidím, jak to činí jazyk jakoby méně elegantní a snad i hůře naučitelný, ale skutečnost je přesně obrácená. Je mnohem jednodušší naučit se a pochopit pár jednoduchých konstrukcí používaných k různým účelům než jednu abstraktnější konstrukci používanou na všechno. I při čtení kódu se pak tyto konstrukce lépe rozpoznávají, všimnu si jich okamžitě. Což se nedá říct třeba o tomhle kódu:

array.dach {|key, value| ... }

Ten se s array.each velmi snadno splete.

v6ak:

Určitě považuji za pllus, když jazyk něco jako ono each umožňuje napsat a nebude to příliš ukecané. Hodí se to totiž na mnoha jiných místech. V PHP třeba někdy používám array_map, ale co je lepší:

a) selectedUsers.map(_.age)

nebo:

b) array_map(function($u){return $u->age;}, $selectedUsers)

A to teď neřeším, co když $selectedUsers nebude pole, ale jiná kolekce. Neřeším ani nutnost použít use v některých případech.

Na druhou stranu uznávám, že velká unverzálnost s sebou nese i zodpovědnost. Kód ve foru se pak může vykonávat třeba i paralelně nebo asynchronně.

ikona Jakub Vrána OpenID:

b) je hrůza, pro tyto jednoduché obraty se v PHP hodí helpery typu ppull(): https://github.com/facebook/libphutil/blob/…/utils.php#L127. Samozřejmě je problém, že nejsou přímo součástí PHP.

Pro cokoliv složitějšího považuji za mnohem čitelnější imperativní zápis. Zrovna včera jsem na toto téma četl pěknou ukázku: https://code.google.com/p/guava-libraries/wiki/FunctionalExplained.

johno:

Tak namiesto toho uzasneho ppull sa da vyuzit v Ruby napriklad zase metoda s blokom array.map {|i| i.name } pripadne rovno idiom, ktory pozna kazdy ruby programator. array.map(&:name) -

Co sa tyka prvoplanovych konstrukcii typu foreach. Nemozem vobec suhlasit. Kde je napisane, ze foreach ma nieco s Traversable? Je to proste jeden konstrukt, ktory sa neda pouzit na nic ine.

"array.dach {|key, value| ... } Ten se s array.each velmi snadno splete." -- Toto je
vtip? Fakt chcete preklep v mene metody vydavat za nevyhodu jazyka? Ale asi tusim kam mierite...

Ja som PHP robil dlhe roky. Ruby mi na prvy krat vyzeralo strasny bordel. Ale to nebolo tym, ze to je bordel, problem je v tom, ze ten jazyk je koncizny a preto sa "na mensom priestore kodu" deje ovela viac. Ale toto nie je ziadny realny problem, je to len nezvyk. Opakujem presiel som si tym sam.

Tak ako vsetci Javisti a PHPckari sa naucili ignorovat boilerplate kod typu, vsetky tie zbytocne {}, $this, -> a vsetky tie zbytocne ukecane konstrukcie ala foreach($array as $key => $value) tak ja ked to teraz vidim, tak ma bolia oci lebo vidim ako si tam zbytocne deriete klavesnice a nicite oci citanim niecoho co sa da napisat 2x kratsie.

ikona Jakub Vrána OpenID:

Jedna z myšlenek, kterou jsem se tímto článkem pokusil vyjádřit, je, že dvakrát kratší neznamená dvakrát lépe čitelný. Některé jazyky jsou na můj vkus moc krátké, některé moc dlouhé, PHP je pro mě tak akorát. Moc si neošoupu klávesnici, kód snadno rozpoznám a není matoucí.

Taky je PHP mnohem jednodušší, protože nemusím dumat, co znamená &:name. Pro mě neznalého Ruby to je úplně strašidelná konstrukce, protože ani nevím, jak si najít její význam bez toho, že se naučím celý jazyk.

v6ak:

S tím, že kratší nemusí být lepší, naprosto souhlasím.

K &:name: Nejsem Rubyista, ale najít to patrně není problém: https://www.google.cz/search?q=ruby+ampersand+colon Hned první odkaz to vysvětluje asi celkem dobře. Aniž bych tuto konstrukci nějak znal, chápu z toho, co dělá ampersand, a asi bych dovedl vymyslet vlastní objekt pro použití s ampersandem.

johno:

Este k each a dach. http://twitpic.com/ddi4n1

ikona Jakub Vrána OpenID:

Ale nebyl by žádný problém udělat, aby to žádnou chybu nevyhazovalo, že ne?

Co jsem se snažil říct, je to, že považuji za výhodu mít konstrukci, která není podobná ostatním konstrukcím a nedá se s nimi tedy ani splést při skimování kódu a je snadno rozpoznatelná.

v6ak:

Jo, ppull je omezené řešení. já chtěl demonstrovat obludnost lambda funkcí v PHP. V případě users.map(_.name.trim), no dobře, tady to ještě tak nějak dáš s ppull+array_map.

Asi se ale neshodneme, že imperativní zápis je vždy lepší u složitějších věcí. Uznávám ale, že pokud jazyk nemá podporu pro stručný zápis lambda funkcí, stane se z toho u funkcionlní verze opruz. I tady to může částečně vyřešit dobré IDE (např. IDEA to řeší nejen při psaní, ale i při čtení, kdy skryje ten balast, nicméně kolegové s jiným IDE nepoděkují). Scala naproti tomu má _.name.trim jako zkratku pro {x => x.name.trim} a kompilátor ještě dořeší typ parametru x podle kontextu. Nebo zahlásí chybu a programátor musí typ specifikovat. Návratová hodnota (zde asi String) se odvodí také.

Je pravda, že jazyky s velkou stručností zápisu mohou trošku svádět k tomu, že člověk nebude ve funkcionálním zápisu používat pomocné proměnné a bude psát velmi dlouhé výrazy bez pomocných funkcí. To už je špatně, ale dá se tomu ubránit. Vlastně člověk musí hlavně převzít některé zvyky, ke kterým je prakticky nucen u imperativního programování, i do funkcionálního programování. To je stejné, jako není dobré psát velké nudle v imperativním programování. Jen tím, že je funkcionální programování úspornější, pravidlo "musí se vlézt na obrazovku" přestává stačit.

Jedna z nevýhod imperativní verze spočívá v tom, že se typicky vícekrát opakuje název výstupní proměnné. To při některých úpravách a kopírování (s tím, že to trochu pozměníme, takže protiargument s DRY neuspěje) může vést k chybám. Další spočívá v tom, že máme příliš přesně v kódu řečeno, jak se to má provést. Jestli sériově, paralelně, apod. Když to chci vyměnit, musím kód přepsat. Ve funkcionální variantě stačí v principu použít jinou funkci, která totéž dělá jinak. (A teď neřeším, jestli jinou funkci vyřešíme na místě, nebo pomocí late binding.)

Nejsem vyloženě funkcionální fundamentalista. Jsem ochoten se "ušpinit" a použít něco imperativního. Na druhou stranu mám stále méně důvodů, proč to dělat. Byl jsem schopen napsat několik stovek řádků čistě funkcionálního kódu, který dohromady řeší jeden konkrétní problém. Není to nějak extra dlouhé, ale zcela určitě to ve srovnání s tím, co tu řešíme s array_map a ppull, je mnohem složitější záležitost. A na funkcionálním přístupu mi tu nepřijde nic obskurního. Rozbít problém na menší celky, použít OOP apod. se dá.

A ještě jedna poznámka: Já jsem si na to zatím až tolik nezvykl (nemám problém použít filter/map/flatMap/...), ale existují konstrukce, které umožňují psát funkcionální kód trošku podobným stylem jako imperativní s for, if apod. Pro ty, kdo jsou zvyklí programovat imperativně, to může kombinovat výhody obou světů. Jde o něco jako:

for{
    user <- users
    if(user.rating > 10)
    comment <- user.comments
    val text = comment.text
    word <- text.split(" ")
} yield (word, user)

Tímto projdu uživatele s hodnocením přes 10, vezmu jejich komentáře, rozbiju je na jednotlivá slova a vracím je jako uspořádané dvojice spolu s uživatelem. Scala to zkompiluje stejně, jako kdyby člověk použil funkce map, flatMap, filter apod. Oproti imperativnímu přístupu získám několik výhod. Kromě již zmíněného opakování názvu výstupní proměnné mohu takto také například získat líný seznam, který se bude načítat z databáze postupně při zpracovávání a nebudu muset načíst tolik dat do paměti. Na to není potřeba přepsat celý kód (navíc do celkem nečitelné podoby), bude stačit použít líné metody, které místo Seq[T] budou vracet Stream[T].

ikona Jakub Vrána OpenID:

Já taky nejsem imperativní fundamentalista, ale je fakt, že funkcionální kód je pro mě často hůř čitelný i zapsatelný. Často se musí číst jakoby odzadu, někde jsem se k tomu obšírně vyjadřoval, ale nemůžu to dohledat.

Výhody, které vypadají tak strašně cool (možnost nahradit sériovou implementaci paralelní), v mém případě většinou nehrají žádnou roli.

v6ak:

Rozdíl v našem přístupu vidím ve dvou věcech:

1. Zvyky. Měl jsem často tendence se vyjadřovat ve funkcionálním stylu. Když vynechám batch files (první programovací jazyk, se kterým jsem se setkal), tak nějaké tendence jsem měl od začátku.

2. Zkušenost. Tím se nechci označit za zkušenějšího programátora, ale možná v FP zkušenější jsem.

3. Jazyk. Odtud patrně pramení Tvoje stížnost, že se funkcionální kód musí číst odzadu. Musí v tradičním Haskellu. Mnohdy musí v tradičním PHP. (V obou případech to lze v principu obejít knihovnou.) Někdy i v Javě. Ale obecně nemusí. OOP s sebou přineslo jednu pěknou věc, která s myšlenkou OOP vůbec nesouvisí, a to je klasický objektový zápis. Následující zápis budu číst zepředu:

val nameFreq = users.groupBy(_.firstName).mapValues(_.size)

Za celkem zásadní výhodu při skimmování kódu považuju, že vidím, kde se do nameFreq přiřazuje. Pokud bych to měl imperativně, musel bych procházet kód a hledat, kde všude do nameFreq zapisuju. Tady ne, navíc to mám kratší.

ikona Lukáš:

Ad čtení odzadu: to mi taky vadí a typicky se to děje, když ty „funkcionální prvky” jsou jako funkce, ne jako metody. Srovnej:

myArray.map(funkce).filter(predikat).take(10)

s

take(filter(map(myArray, funkce), funkce), 10)

To první je krásně čitelné, to druhé bych se neodvážil napsat. Docela hezky to řeší třeba LiveScript se svým |> operátorem (přebral ho myslím z jiného jazyka, nevím kterého). To je další věc, které mi vadí na Pythonu, ten má právě map jako funkci, takže se podobnému vnořování vyhýbám.

Jakub Kulhan:

Psát obj.hasOwnProperty(...) je opruz, ale možnost napsat $.each(...) je podle mě OK - proč by mělo být špatné, že jazyk je expresivní natolik, že lze napsat takový kód na user-level? To je jedině dobře. A zase u procházení pole v Javě - tak, jak je to v článku to prostě nikdy nenapíšeš, nebo to aspoň nikdy nepíšeš celé (jak psal v6ak, importy řeší IDE, snad nikdy jsem nepsal import třídy v Javě ručně).

"Placatost" PHP má trochu jiný efekt - lidé píší jednoduše. V Javě si můžu udělat milion packages (btw packages v Javě, i když se tváří, že jsou zanořené, jsou ploché - pozná se třeba, když se chce použít nějaká reflexe), do každého nasekat milion tříd a všem je to jedno, protože to je v mém jméném prostoru - dá se tím pracovat v dalších projektech, aniž by se to bilo. Když v PHP nebyly namespaces, všechno bylo v globálním jménném prostoru, prostě jsem nemohl vymyslet milion tříd, nejrůznější bridge, adaptery atd. - tak jsem to udělal jednoduše do jedné a bylo.

Signatura fce v Javě je jasná. Možná není stručná, ale je jasná. public static partition(array $list, $size) v PHP je taky jasná signatura. Poskytuje míň informací než ta v Javě, ale v PHP je to prostě běžné. Každý jazyk má svůj styl.

S anotacemi je to stejně jako se vším. Když jsou overused, je to na škodu věci. Ale jinak je to super věc.

Mám rád Javascript, PHP a naučil jsem se mít rád Javu - ale ji až potom, co jsem přešel na pořádné IDE, Intellij IDEA. Každý jazyk se hodí na něco a nejde ve všech programovat stejně. Podle mě je potřeba každý jazyk používat k pokraji jeho možností - v Javascriptu si napsat foreach() fci, v Javě nad všechno nacpat anotaci, v PHP mít třídu __get()&__set()&offsetGet()&..., a to je podle mě jedině správně.

ikona Jakub Vrána OpenID:

Na možnosti (spíše nutnosti) napsat $.each() je špatně několik věcí. V první řadě když přijdu k nějakému cizímu kódu, tak musím studovat, jaké rozšíření vlastně používá, jak se chová a co všechno umí. Dále vytvořená konstrukce není tak expresivní, jako když by byla přímo součástí jazyka. U kódu „$.each(a, function (b, c) {})“ není jasné, jestli v b bude klíč nebo hodnota. U kódu „foreach ($a as $b => $c) {}“ to je na první pohled patrné.

Jazyk, ve kterém si můžu (nebo dokonce musím) vytvořit vlastní jazyk, nepovažuji za příliš dobrý. Považuji za velké selhání PHP, že prakticky nejde použít jako šablonovací jazyk (přestože jako jeden prakticky vznikl) a že musí vznikat jazyky nezávislé. Považuji za velké selhání JavaScriptu, že vzniklo „$.each(list, function (key, value) {})“ a zároveň „_.each(list, function (value, key) {})“.

ikona Lukáš:

„není jasné, jestli v b bude klíč nebo hodnota”
Existuje nějaký jazyk, který by při procházení slovníku vytvářel dvojice klíč—hodnota naopak? Tj. že by hodnoty ukládal do dvojice (x, y), kde je x je hodnota a y klíč?

Já mám třeba u PHP zase ten problém, že nikdy nevím, jestli je jako první píše kolekce, nebo prvek. Což může být dáno tím, že PHP je snad jediný jazyk, na který si teď vzpomenu, který má $array as $item místo $item in $array.

v6ak:

Nejsem si jist, ale u callbacků bych se tomu nedivil. Uvědom si taky, že na funkci (A) => R se můžeme v JS dívat i jako na funkci (A, B) => R pro libovolný typ B. Takže člověk může chtít jen hodnoty (to bude chtít spíš než jen klíče) a napsat $.each(a, function (value) {}).

A konkrétní příklad, kde je to naopak, může poskytnout například funkce Array.prototype.map: http://stackoverflow.com/questions/14528397/…-map-parseint

ikona Lukáš:

To je metoda pole, ne slovníku. U pole mi přijde pochopitelné, že je první hodnota a až pak (volitelně) klíč (index).

v6ak:

Jsou jazyky, které stírají ten rozdíl. Například PHP nebo JavaScript. Pak dává smysl oboje pořadí parametrů. Stejně u each.

ikona Jakub Vrána OpenID:

Příklad jsem uvedl v předchozím komentáři. Knihovna Underscore.js dává do prvního parametru hodnotu a dává to docela dobrý smysl – hodnotu potřebuji častěji než klíč, takže callback s jedním parametrem dostane pouze hodnoty.

„$array as $item“ nebo „$item in $array“ je úplně jedno – čitelné je to stejně, na zápis stejně složité, ani v jednom se nedá udělat chyba. Ale když srovnám „$array as $key => $value“ s „key, value in array.items()“, tak jednoznačně vyhrává to první – jak na čtení, tak na zápis, tak na komplikovanost udělat chybu.

ikona Lukáš:

Škoda, doufal jsem, že to nikdo naopak nemá :-). Mně to moc rozumné nepřijde, asi programuji nějak jinak, ale když už někde použiji slovník, tak ho mnohem častěji potřebuji projít přes klíče i hodnoty, než jen přes hodnoty. Proto mě ostatně rozčiluje, že v Pythonu nemůže napsat for k, v in slovnik, ale musím tam přidávat i to items().

A nemůžu si pomoci, ale „foreach ($a as $b => $c) {}“ je pro mě méně přehledné než třeba způsob v Pythonu nebo C#, po každé, když to v PHP píšu, tak se musím zamyslet, co kam mám napsat. Ale to bude tím, že to PHP má naopak a místo „in array” má „array as”. Opět — všechny jazyky co znám používají buď callback nebo „in array” a to včetně nějakých pseudokódů ve vědeckých článcích nebo obyčejného zápisu v matematice \forall x \in N :-)

To, že si musíme v JS dopisovat vlastní použitelné procházení polí/objektů také považuji za špatnou věc, ne za dobrou. Co už.

ikona Aichi:

Jakube, muzes prosim te rozvest tvoji uvahu o funkci pri prochazeni objektu v Javascriptu? Vubec nechapu na co si stezujes.

ikona Jakub Vrána OpenID:

Nejsem si jist, kterou úvahu máš na mysli. Vadí mi dvě věci:

1. V čistém JavaScriptu bez žádné knihovny se nedají projít hodnoty objektu vráceného funkcí bez pomocné proměnné. Musím napsat.

var f = f(); // to je ta pomocná proměnná, která mi vadí
for (var key in f) {
  var value = f[key];
}

2. S pomocnou knihovnou se do sebe funkce hodně zanořují. Následující kód považuji za míň přehledný než předchozí ukázku:

jQuery.each(f(), function (key, value) {
});

ikona Aichi:

Ahoj, diky u jasneni. V tom mas pravdu, neda se udelat automaticka expanze a bez prirazeni se k hodnote nedostanes:

function f () {
  return {a:1,b:2,c:3};
}

for (var p in f()) {
  console.log(p)
}

jde to samozrejme zdrcnout tak aby to vypadalo podobne jako v PHP, ale to asi neni cilem a explicitni deklaraci pomocne promenne se nevyhneme:

function f () {
  return {a:1,b:2,c:3};
}

var p,a;
for (p in  (a = f())) {
  console.log(a[p])
}

bene:

Jako vývojáři v PHP mi právě chybí možnost napsat typ do definice metody místo do phpdoc.

Kéž by tak šlo napsat:

<?php
public function array partition(array $list, int $size) {
}
?>

A ještě lépe:

<?php
public function array<MyInterface> partition(array<MyInterface> $list, int $size) {
}
?>

namísto

<?php
/**
* @param array $list
* @param int $size
* @return array
*/
public function partition(array $list, $size) {
}
?>

Bohužel pokud se něco takového do PHP dostane, bude to opět jako jiné přidané potřebné featurky, ve sprasené podobě.
Něco jako:

<?php
public function array partition(array $list, (int) $size) {
}
?>

A uvidíme milión závorek.

Když jsem řetl RFC, tak mě napadnul jediný logický důvod, proč vůbec někdo takovou hrůzu navrhuje namísto jednoduché první varianty. Zpětná kompatibilita. V případě bez závorek by bylo int označeno za klíčové slovo. Form::INT by bylo najednou problém. Nevím, jestli je to problém překladače, který nedokáže pracovat v různých kontextech. Nebo by to překladač zvládl, ale problém je v nazvu třídy Int, kterou by měl někdo jako typehint.

maryo:

Hlavní důvod je ten, že v php je zvykem nerozlišovat číslo a číselný řetězec, resp. se buď přetypovává, nekontroluje skalární typ nebo používá is_numeric apod. Takže závorky proto, že to bere cokoliv přetypovatelné na např. int.

Honza77:

Tento zvyk je ale celkem špatný, protože když chci někde int a někdo mi pošle string "automobil", tak je prostě něco špatně. Pokud to přetypovávám na int, tak to potichu projde s nulou. A pokud tam nacpu array('foo', 'bar'), tak to projde s jedničkou. Ale v takovém případě to má řvát chybu (potlačování chyb vede do pekel, i když potlačování chyb mají méně pokročilí uživatelé rádi).

Honza77:

Tohle je naprosto přesné. Typy v komentářích, jsou velmi nepraktické. Stejně tak vědět, že někam mám strčit pole, ale už nevědět jakého typu mají být prvky toho pole. Ovšem, co když budu potřebovat do parametru dávat něco složitějšího? Třeba budu očekávat u pole klíče typu string a hodnoty typu pole intů? Aby bylo možné zapsat opravdu skutečný typ, tak by byly třeba komplexní zápisy jako u generik. Další problém vidím v tom, že vestavěný array je jedna z mnoha možných kolekcí. Pokud bych mohl určit array<int>, jak bych určil třeba spojový seznam intů? Mohl bych si udělat třídu "IntLinkedList", "StringLinkedList" atd., což je nepraktické. Nebo bych si mohl udělat obecný LinkedList, ale už bych nemohl v typu určit, že jde o spojový seznam intů. Prostě to stejně vede na zápisy obdobné generickým typům. C# ve své první verzi generické typy neměl a kolekce braly cokoli (potomky třídy objekt). Ale generika mají mnohem lepší vyjadřovací schopnost a velmi se osvědčila.

Prostě nemůžu si pomoci, v PHP to bude pořád nějaké takové napůl (tedy spíše ani to ne).

ikona Jakub Vrána OpenID:

Souhlasím, type hinting by se mi v PHP líbil také mnohem pokročilejší. HipHop for PHP používaný ve Facebooku umožňuje type hinting i u skalárních typů, byla velká úleva moci to používat. Kompilátor dokonce tuto informaci využívá pro optimalizaci, takže to činí kód nejen explicitnější, ale i rychlejší.

Snadno zapsat komplikovanější typy hinty je výzva, Javě se to podle mě nepovedlo. V PHP by mi asi kromě skalárních typů stačila možnost zapsat pole jiných typů stylem f(Item[] $items). Do Phabricatoru jsem alespoň udělal funkci assert_instances_of(), kterou voláme na začátku metod, které přijímají pole: https://github.com/facebook/libphutil/blob/…/utils.php#L529.

Neodpustím si srovnání s Pythonem, který type-hinty nemá vůbec. Podle mě je to jeho velká slabina.

TSe:

mě PHP vyhovuje v podstatě z podobných důvodů zde uvedených, kvuli silné typovosti jsem pak přešel na C#.

udělal bych i článek "co mi na PHP vadí"

za mě asi
1) nekonzistence v logickém pořadí parametrů u některých funkcí
např:
strpos ( string $haystack , mixed $needle)
vs
array_key_exists ( mixed $key , array $search )

2)netypovost - někdy strašná výhoda a rád ji využívám, ale občas je na obtíž, zejména při přejímání kodu od jiných :-)

ikona Jakub Vrána OpenID:

Co je špatně na PHP velmi dobře popsal slavný článek „PHP: a fractal of bad design“. Já jsem k němu měl pár výhrad (http://php.vrana.cz/php-a-fractal-of-not-so-bad-design.php), ale jinak s ním v zásadě souhlasím.

Nekonzistenci pořadí parametrů považuji za podobnou malichernost jako nutnost uvádět, odkud se má v Javě naimportovat Map. Dokonce i jednoduchý editor to napoví a osobně jsem s tím nikdy neměl problém ani při čtení kódu. Ale je pravda, že to je zbytečná nekonzistence daná jen živelným vývojem.

lenochware:

No ten clanek je psany velice zaujatym tonem a vsechny ty php hejty me uz dost otravuji. Ony ty druhe jazyky taky nejsou ve vsem tak dokonale.
Je pravda, ze z hlediska designu je na tom php dost bidne. Historicky se v nem realizovaly vselijake koncepty a pristupy a nektere veci skutecne nejsou moc povedene. Ale prece dulezitejsi meritko, nez dokonala a konzistentni architektura, je prakticnost, pohodlnost a rychlost se kterou se v tom jazyce realne pracuje. A troufam si rict, ze z tohoto hlediska na tom php neni zas tak spatne. Alespon me se s nim subjektivne ze vsech jazyku, co jsem zkousel, pracovalo vzdycky nejprijemneji.
Pak je tu jeste otazka kvality vysledne aplikace. Mozna, ze jazyk s perfektnim designem vede k tvorbe kvalitnejsich aplikaci. Jenze vim o webaplikacich v jave a v .netu, ktere jsou zabugovane, pomale a mizerne, takze myslim, ze to taky tak uplne neplati.
Imho pripadne nedostatky aplikaci v php jdou na vrub spis nez nedostatkum v jazyce tomu, ze diky snadnosti se kterou lze zvladnout zaklady php, ho pouziva i hodne nezkusenych programatoru...

Honza77:

Jakube, můžeš prosím také srovnat se C#? Ponechme stranou, že jej udělal Microsoft a že je doma na Windows (i když existuje Mono apod.), a zkusme se zaměřit jen na jazyk a principy platformy. Já v něm vidím jakéhosi nástupce PHP - tedy podobná syntaxe, ale opraveno spousta věcí a doplněny nové možnosti. Oba jazyky (a nejen tyto) znám dlouho a v obou aktivně dělám, mám zkušenosti s čitelností cizích kódů. C# je někde o něco trochu ukecanější, ale umožňuje to lepší čitelnost a automatickou kontrolu kódu. Při práci zejména s cizím kódem ohromný pomocník.

Po těch stránkách, které zmiňuješ:
- jednoduchost - C# se snaží být jednoduchý, ale zároveň dostatečně popisný (proč např. neuvádět typy do deklarace metody a psát to někam vedle do komentáře?)
- nadužívání jmenných prostorů v C# není běžné a nepůsobí většinou žádné problémy
- pokročilé obraty C# obsahuje - od základů jako viditelnost proměnných (ale např. i konstant, na což PHP kašle) až po věci jako LINQ, což je úžasný výrazový prostředek (stručný, při rozumném používání dobře čitelný a bezpečný)
- magie - většinou téměř žádná, všechno lze snadno dohledat
- anotace - C# podporuje a nepůsobí v praxi žádné problémy, ale naopak často zjednodušují život
- generika a typový systém - výborná věc - umožňuje zápis typů, který má dvě funkce - kontrolní a dokumentační. Type inference zestručňuje zápisy, ale pořád umožňuje jak kontrolu, tak dokumentační schopnost (napovídání apod.). Zápis typů včetně snadného odvozování typů s pomocí generik umožňuje jasně vyjádřit, co např. daná metoda požaduje za parametr nebo co vrací. Pokud budeš porovnávat zápis generik s ničím, tak generika budou vypadat složitě. Ale pokud nemáš generika, tak musíš typ vyjádřit nějak jinak - popisem v dokumentaci. A zápis generického typu v takovém případě typicky v čitelnosti vyhrává a protože je standardizovaný, tak jej každý hned pochopí. Kompilace a statická analýza jsou zde velmi silný nástroj (oproti PHP, kde sice nějakou statickou analýzu lze dělat také, ale oproti C# s mizernými výsledky).

Samozřejmě jsou výjimky, kde se silná typovost nehodí, ale s tím C# také nemá problém.

Na každé vývojové platformě se najdou nějaké mouchy nebo případy, kdy nebude vhodné ji
použít. C# vzniklo poměrně pozdě a pořád se poměrně rychle vyvíjí. Poučilo se mimo jiné z Javy, která je opravdu dost ukecaná (a někdy to má i negativní vliv na čitelnost) a některé věci se v ní píší poměrně špatně.

Co ti trhá žíly v C# po stránce jazyka/principu platformy? Já mám také s některými jazyky obdobné problémy, které mi hodně vadí a byl bych hodně rád, kdyby byly jinak. U C# ale tyto pocity nemám (kromě nějakých marginálií) - pokud vidím někde nějakou nevýhodu, tak za ní vidím zcela jasný úmysl a nějakou podstatnější výhodu, kterou to rozhodnutí umožnilo. U PHP vidím spoustu nevýhod, ze kterými není žádná výhoda, ale jen chaotický historický vznik a nutnost alespoň částečně držet zpětnou kompatibilitu.

ikona Jakub Vrána OpenID:

C# bohužel neznám. Mám pocit, že z nějakého důvodu k němu panuje obecná averze – ani ve Facebooku ani v Google se nepoužívá, přestože jiných jazyků se používá celá řada. Mám za to, že to je dané především tím, že za ním stojí Microsoft a primární platforma je Windows, což jazyk diskvalifikuje ve firmách, kde všechny servery jedou na Linuxu a přes 90% vývojářů používá Mac.

Druhým důvodem je možná to, že jazyk přišel pozdě a obecně není vnímán jako natolik odlišný od Javy, aby se na něj vyplatilo přecházet. Kdo ví.

Každopádně doufám, že si C# někdy na nějakém skutečném projektu budu moci vyzkoušet. Z toho, co o něm vím, mám pocit, že by mi mohl sednout, možná i na úrovni PHP.

Milsa:

Existuje aj Mono pre Linux.

Milsa:

Keby robíš hlavne v Jave, chváliš tú. Mne sa tak pre jednoduchosť páči CodeIgniter. A určite sú aj lepšie frameworky.

Taco:

Mám rád PHP, protože ho velmi dobře znám, a protože mne živí. Díky tomu, že ho dobře znám, tak je pro mne snadné ho používat. To je asi tak všechno. Žádné další výhody u něj nevidím.

Porovnávat PHP s Javou mi vyjde vždycky líp pro Javu. Posuzovat typovou definici Javy proti strohosti PHP je nefér. A asi to nemá smysl vysvětlovat, protože to imho takto píšeš schválně :-)

enumag:

S článkem většinou souhlasím až na beztypovost. Respektive beztypovost by mi ani moc nevadila pokud by v PHP byl použitelný typehinting pro skalární typy, ale to již několikrát zmíněno v komentářích takže to nebudu rozvádět.

Co mi ale v PHP vadí asi nejvíce jsou všudypřítomná a až příliš mocná (a kvůli tomu i pomalá) pole namísto několika různých datových struktur. Samozřejmě vím o SPL Datastructures, ale kdo je používá?

ikona Jakub Vrána OpenID:

Pole v PHP mají dobrou asymptotickou složitost pro všechny operace. Mně to naopak přijde taky jako zbytečná složitost Pythonu, který má místo jednoho pole jako v PHP čtyři různé datové struktury.

v6ak:

Snad jen v jednom případě jsem to považoval za výhodu PHP - potřeboval jsem mapu, ale klíče jsem chtěl mít seřazeny vyjmenovaným způsobem.

Jindy mi to přijde spíše nepříjemné. Jak v PHP reprezentovat množinu? OK, to ještě jde přes indexy (fuj!). Horší je, když to chceme použít např. pro objekty.

Nevýhoda je to i z hlediska dokumentace. Napříkad Map[Int, Int] nebo Set[String] mi řekne mnohem víc než pouhé array. Někdy to je z kontextu zřejmé, někdy ne. A někdy si obě strany myslí, že je to jasné, ale každá to vidí jinak.

lenochware:

Hm, ja zas univerzalni a flexibilni php pole povazuju za jednu z velkych vyhod oproti jinym jazykum. Nemusim premyslet jakou z mnoha kolekci vybrat, muzu kombinovat ruzne typy bez komplikovanych javovskych sablon...
Snadnost prace s kolekcemi dat je podle me zakladni prednost, stejne jako snadnost prace se stringy - protoze se to pouziva neustale.
Co se tyce vykonnosti, tak typicky to uzke hrdlo imho byva jinde nez v polich...

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 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.