V čem je PHP navrženo lépe než Java

Existuje spousta článků, které kritizují návrh PHP, nejznámější je asi PHP: a fractal of bad design. Na ten jsem napsal jen poměrně krátkou reakci, protože se zbytkem článku v zásadě souhlasím. PHP je skutečně v mnoha ohledech špatně navržený jazyk. V čem je ale navržený lépe než Java?

Anonymní funkce

Java dlouhou dobu neměla anonymní funkce a tzv. lambda expressions zavedla až letos. Do té doby se používaly jen krkolomné anonymní třídy. V PHP jsou naproti tomu anonymní funkce už pět let (2 roky s podporou $this) a do značné míry změnily, jakým způsobem se v PHP programuje.

Nutnost používání $this

V PHP se musí při přístupu k vlastnostem a metodám objektů vždy uvádět $this. V Javě to není potřeba, tedy pokud název vlastnosti nekoliduje s názvem lokální proměnné. Zní to jako výhoda Javy, ale mně dalo dost práce, než jsem si na to zvykl. Při pohledu do kódu Javy často přemýšlím – je tohle lokální proměnná, vlastnost objektu nebo je snad deklarovaná v rodiči? Připomíná mi to doby register_globals, kde jsem také často dumal, kde se nějaká proměnná vlastně vzala.

Hodnota null

V Javě je hodnota null implicitně povolená u všech neprimitivních datových typů. Ošetření této hodnoty prolézá kódem jako rakovina. Existuje pokus o řešení v podobě anotace NotNull, ale její použití a ostatně i definice jsou nejednotné. Jiný pokus o řešení téhle hrůzy je nově uvedená třída Optional, místo které ale taky můžete dostat null… V PHP naproti tomu jde do parametru s type hintem poslat null, jen pokud je volitelný. Je velká úleva nemuset v těle funkce přemýšlet o tom, jestli mi náhodou někde nemůže přijít null.

Volitelné parametry

Java nezná volitelné parametry. Místo toho si můžete nadefinovat více metod stejného jména, které přijímají různé parametry. V některých situacích se dají použít i varargs, které mimochodem do jazyka byly dohackované neuvěřitelným způsobem (lze je předat jako seznam parametrů nebo jako pole, takže pokud chcete předat jediný parametr obsahující pole, tak se pěkně zapotíte). Přetěžování metod obecně nepovažuji za dobrý nápad, často v kódu koukám na volání a lámu si hlavu tím, co se vlastně zavolá, a odpověď často poskytne až IDE. Přístup PHP, kdy jeden název může mít jen jedna metoda, mi vyhovuje mnohem víc. Jen je škoda, že pokud parametr může být různých typů bez společného předka, musíme oželet type hint. V tomhle se mi líbí Closure, kde se sjednocení různých typů používá zcela běžně.

API pro regulární výrazy

Java má hezký koncept explicitní kompilace regulárních výrazů. V PHP se zkompilované regulární výrazy automaticky kešují a programátor nad tím nemá kontrolu. To nevadí u krátkých skriptů, ale u dlouhoběžících aplikací (např. démonů) to může být problém, obzvlášť pokud někdo vytváří regulární výrazy dynamicky. Potíž s Javou je v tom, že funkce pro pohodlnou práci s regulárními výrazy String.matches a String.replaceAll přijímají regulární výraz ve tvaru řetězce a nikoliv jeho zkompilovanou podobu. To by mimochodem bylo jedno z mála smysluplných použití přetěžování. V Javě si tedy můžete vybrat, jestli budete používat pohodlné API s anti-patternem (za který se opakované používání nezkompilovaných regulárních výrazů považuje) nebo API nepohodlné. Mimochodem rozlišit metody přijímající řetězec nebo regulární výraz pomocí názvů replace a replaceAll nepostrádá notnou dávku zbabranosti.

Inicializace polí a map

Java dovoluje inicializovat pole konstrukcí {}, bohužel to jde ale jenom u deklarace. Předávání pohotově vytvořeného pole by se hodilo třeba v testech. Pole si musíte přiřadit do proměnné a tu teprve poslat funkci. Že byste proměnnou přepsali nějakým jiným pohotově vytvořeným polem, na to rovnou zapomeňte a na inicializaci map raději ani nemyslete. Když chcete vytvořit třeba konstantu s mapou, musíte ji inicializovat ve statickém konstruktoru. Guava nabízí alespoň jednoduchou možnost vytvoření ImmutableMap, na vytvoření Map ale nic standardního není. V PHP jde pole inicializovat triviálně, včetně přiřazení klíčů.

Pole a seznamy

Java vznikla s podporou polí (array), později doplnila také seznamy (List). Obojí se používá v zásadě pro to stejné, některá API používají pole, jiné seznamy. Trochu mi to připomíná nejednotnost PHP v chování k nativním polím a ArrayObject, zmatek v Javě je ale přeci jen o poznání větší.

Iterace

Java 1.5 přinesla jednoduchou možnost iterace pomocí for each. Pokud ale chcete procházet klíče i hodnoty mapy, tak se i s touto konstrukcí pěkně zapotíte. Asi nejčistší je použití metody entrySet, která vrací Map.Entry, na které můžete zavolat getKey a getValue. To by se místo:

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

… nemohlo psát třeba for (String key, String value : map) {}? V PHP je iterace klíčů i hodnot polí maximálně pohodlná.

Zbytečné přetypování

V Javě je potřeba na mnoha místech zbytečně přetypovávat. Např. v tomto kódu:

if (x instanceof String) {
    f((String) x);
}

To by si kompilátor nemohl domyslet, že x nemůže být jiného typu než String? Closure Compiler to zvládne. V PHP žádné přetypování na třídy neexistuje.

Kompilace

PHP skript spustíte a okamžitě běží. Java se nejprve musí zkompilovat, což je např. ve srovnání s Go neuvěřitelně zdlouhavý proces. Kompilace má svou výhodu v tom, že se při ní zaručeně dozvím o chybách, na které by se při běhu ani nemuselo narazit. V PHP tuto roli suplují lintery. Kompilaci a spuštění bych si představoval oddělené. Nerad bych se vzdával všech chyb, o kterých se díky kompilaci dozvím, zároveň bych ale chtěl mít možnost program rychle spustit. Java stejně zkompilovaný bajtkód optimalizuje při běhu, to by to nemohla dělat rovnou ze zdrojového kódu?

Porovnávání řetězců

Řetězce jsou v Javě objekty, takže se nedají porovnávat operátorem ==. Místo toho musíte použít metodu equals, takže místo $a != "a" se obvykle píše podle mě zcela nepřehledné !"a".equals(a). Nejhorší ze všeho je, že Java používá tzv. string interning, takže program porovnávající řetězce pomocí == bude normálně fungovat až do té doby, kdy z ničeho nic fungovat přestane.

import *

Když PHP zavedlo jmenné prostory, tu a tam někdo naříkal, že nepodporuje import všech objektů z daného jmenného prostoru. Java tuto možnost má a v jednorázovém skriptu se docela hodí napsat si import java.util.* nebo něco podobného. V seriózních projektech jde ale o anti-pattern, protože co se asi stane, když nějaký jmenný prostor přidá třídu, jejíž název už používáte z jiného jmenného prostoru (ideálně také přes hvězdičku)?

Vlákna a synchronizace

Může být užitečné vytvořit si více vláken, ale způsob, jakým se s nimi potom v Javě pracuje, je tak nízkoúrovňový, že bych se bez toho snad radši obešel. Mluvím především o potřebě synchronizace. Přístup PHP, kde všechno běží v jednom vlákně nebo procesu a o spuštění více věcí najednou se stará webový server, mi vyhovuje mnohem víc. Když už je někdy potřeba dělat víc věcí najednou v rámci jednoho skriptu, tak je to obvykle čekání na výsledek, a to jde v PHP poměrně snadno pomocí futures. Ostatně i v JavaScriptu plném callbacků najednou běží vždy jen jeden kód.

Závěr

Článek se jednostranně zaměřuje na nevýhody Javy ve srovnání s PHP z mého pohledu. Rozhodně nejde o nezávislé porovnání obou jazyků, ale spíše o ukázku toho, kde měli tvůrci PHP šťastnější ruku. Napadají vás další oblasti, kde je Java špatně navržená? Podělte se o ně v diskuzi. Naopak se prosím zdržte kritiky PHP, ať se zaujatý pohled článku zbytečně nerozmělní.

Autor pracuje jako Software Engineer v týmu Gmail Security. V minulosti se zabýval především PHP, o kterém napsal knihu a podílel se na oficiální dokumentaci. Je autorem nástroje pro správu databáze Adminer. Poznámky si zapisuje na weblog PHP triky.

Komentáře: 115

Přehled komentářů

klokane Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
klokane Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
LesTR Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
Kinkos Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
Martin Hassman Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
Kinkos Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
Martin Hassman Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
LesTR Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
Martin Hassman Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
Dodo Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
Martin Hassman Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
Jakub Vrána Re: Titulek by měl znít spíše "v čem mi více vyhovuje PHP než Java"
steida
foobar ad zbytecne pretypovani
Michal H Díky
icaine Re: Díky
KarelI
David Grudl tl;dr
steida Re: tl;dr
Re: tl;dr
Jirka Kosek Re: tl;dr
mmx Ok.
icaine Re: Ok.
Jakub Vrána Re: Ok.
jehovista Re: Ok.
Jakub Vrána Re: Ok.
h Re: Ok.
jehovista Re: Ok.
Jakub Vrána Re: Ok.
podlesh Re: Ok.
Jakub Vrána Re: Ok.
jehovista Re: Ok.
vaclav.sir Začínající seniory?
Jakub Kulhan Jabka a hrušky
roxtri Fajn článek
KarelI Re: Fajn článek
Tomas Dvorak Re: Fajn článek
KarelI Re: Fajn článek
roxtri Re: Fajn článek
mikiqex Re: Fajn článek
DavidGrudl Re: Fajn článek
mkoubik Re: Fajn článek
mikiqex Re: Fajn článek
mikiqex Re: Fajn článek
Radek
icaine Re:
Vindis Re:
Radek Re:
Vindis
pp některé body jsou subjektivní až moc
MK Výhody x Nevýhody
Tibor Vlákna a synchronizace
Jakub Vrána Re: Vlákna a synchronizace
Luboš Račanský Další čtení
Svaťa Callbacky
KarelI Re: Callbacky
vaclav.sir Re: Callbacky
lubosdz stringy, localization
KarelI Re: stringy, localization
Jakub Vrána Re: stringy, localization
lenoch
icaine Re:
Samuel Java vs. PHP, nemám názor
Jakub Vrána Re: Java vs. PHP, nemám názor
svatal Kotlin
mschayna Groovy
M.K Re: Groovy
Joh Stringy, equals
Kinkos Re: Stringy, equals
Koubel
Martin Hassman Re:
Daniel Re:
lenoch
Kinkos Re:
lenoch Re:
Kinkos Re:
RH Multivlaknovost
Jakub Vrána Re: Multivlaknovost
RH Re: Multivlaknovost
KitSaels Proč mám raději PHP
Martin Prokeš bitka zastydlých pamětníků
Martin Hassman Re: bitka zastydlých pamětníků
Jiří Re: bitka zastydlých pamětníků
Martin Hassman Re: bitka zastydlých pamětníků
xmx. Re: bitka zastydlých pamětníků
Martin Hassman Re: bitka zastydlých pamětníků
Jirka Kosek Re: bitka zastydlých pamětníků
xmx.
lenoch Re:
Jakub Vrána Re:
Martin Prokeš
KitSaels Re:
Tomáš Brukner
Jakub Vrána Re:
michal
Jakub Vrána
Dmitrij Co jsou lintery?
Jakub Vrána Re: Co jsou lintery?
Zdeněk Troníček Důvody
v6ak
Radek Re:
David Šauer Re:
v6ak Re:
v6ak Re:
Vojta Hotove veci v PHP
Zdeněk Troníček Re: Hotove veci v PHP
Blažoun Když PHP kodér píše o Javě
v6ak Re: Když PHP kodér píše o Javě
Jakub Vrána
Blažoun Re:
Daniel Kec Java se kompiluje dvakrát
Lemming
Taskkill Více vlákno/ paralelní programování
Jakub Vrána Re: Více vlákno/ paralelní programování
Miloš brecher Jsem velký fanoušek PHP
Zdroj: https://www.zdrojak.cz/?p=12710