Na navigaci | Klávesové zkratky

Translate to English… Ins Deutsche übersetzen…

Jsem zděšen z PHP5

Víte, co je největší předností Zend PHP Framework? Že donutil programátory Zendu objektově psát ve svém jazyku. Právě díky tomu by PHP6 už mohl být skutečně plnohodnotný objektový jazyk. Ale postupně…

Kterak Zend doplatil na PHP

PHP Nejprve jednu veselou perličku. V prosinci minulého roku uveřejnil Zend webcast prezentující některé vlastnosti připravovaného frameworku. Načež se ozvalo pár programátorů s výtkou, že předváděné věci nelze technicky v PHP vůbec implementovat. Tak dělá si z nás Zend legraci?

Konkrétně šlo o práci se statickými prvky tříd. Ty jsou v PHP kvůli několika vadám (např. konstrukce self::) v podstatě nepoužitelné. Obyčejný Singleton si v PHP nenapíšete…

Ovšem ta perlička má velmi zajímavé historické pozadí. Na vadnou implementaci self:: bylo upozorněno před více než dvěma lety! Tedy ještě dlouho před vypuštěním PHP5. Všechny tyto bugreporty však skončily označené jako „bogus“, „wont fix“ nebo „double-check the documentation“, pěkně o tom píše Elizabeth Marie Smith. Tvůrci objektového PHP prostě ani objektově ani v PHP nepíšou (používají C). A taky to tak vypadá.

Ovšem nejen statické prvky, tedy velká novinka PHP5, je v PHP5 nepoužitelná. No, a ještě je tu další fíčůrka.

Záhadný overloading

Overloading je nepochybně skvělá věc. Rád ho používám i jako „důrazné varování“ při přístupu k neexistující proměnné objektu:

class Test {
    public $n;

    function __get($name)
    {
        $class = get_class($this);
        user_error("Undefined property $class::\$$name", E_USER_ERROR);
    }

    function __set($name, $value)
    {
        $class = get_class($this);
        user_error("Undefined property $class::\$$name", E_USER_ERROR);
    }
}

$foo = new Test();
$foo->n = 1; // ok
$foo->x = 1; // fatal error

Nicméně jeho hlavní potenciál spočívá samozřejmě jinde. Tedy spočíval by, kdyby fungoval, jak má.

Vezměme si pole dostupné přes overloading a změníme mu prvek:

$foo->arr = array('hello', 'php');
// tedy jako:
//    $foo->__set('arr', array('hello', 'php') );

$foo->arr[0] = 'bye';
// tedy něco jako:
//    $bar = & $foo->__get('arr');
//    $bar[0] = 'bye';
//

Podstatné je, že __set() se při změně prvku pole nevolá, tedy __get() musí vrátit na pole referenci. Jenže podíváte-li se na příklad v dokumentaci, uvidíte, že __get() nevrací referenci, nýbrž kopii. Dokonce kopii kopie, protože si pole uloží ještě do proměnné $r. Tedy uvedený příklad by vůbec neměl fungovat. On však funguje. Toho je možné dosáhnout jedině nějakým hackem jádra. Overloading je hra nečistá.

Co čert nechtěl, před pár dny jsem narazil na závažnou chybu, která mě od něj naprosto odradila. Takže teď přepisuju kód Nette a dávám overloading pryč.

Doplněno: V PHP 5.2.0 sice nefunguje overloading téměř vůbec, ale od verze 5.2.1 je zde uvedená chyba (konečně) odstraněna.

Tedy druhý významný rys PHP5, který je nepoužitelný.

Blýskne se na lepší časy?

Zend implementuje každou vlastnost dvakrát: poprvé blbě, podruhé lépe. Objektový model PHP5 je mizérie a každou chvíli musím přemýšlet, jak to či ono obejít. Ale jsem optimista – vývoj Zend PHP Frameworku situaci změní. Už teď totiž programátoři Zendu na vady PHP velmi tvrdě narážejí a jak se zdá, díky nim vývoj frameworku malinko usnul. Vivat PHP6!


Související:

Komentáře

  1. llook http://llook.wz.cz/weblog/ #1

    avatar

    Hurá, PHP6 bude použitelné! Zatím jsem k tvrzením typu „nejvyšší čas opustit PHP“ byl skeptický, ale asi úplně zcestná nejsou.

    Jenže kam? Python a Ruby jsou fajn, ale na pracovním trhu po nich prakticky není ani nabídka (programátoři), ani poptávka (zaměstnavatelé).

    před 11 lety | reagoval [10] Michal Hantl
  2. Petr Stříbný http://stribny.name/zapisnik/ #2

    Taky jsem v PHP začal nedávno objektově programovat a chvilku mi trvalo se odnaučit některé věci z jazyků jako je C#. A pořád přemýšlím, jestli ty objekty v PHP budou mít nějaký smysl, skutečnou výhodu.. Opravdu jsou některé věci v PHP divné..

    před 11 lety
  3. Mirek Novotný #3

    Pamatuju si, jak jsme říkali VIVAT PHP 4! PHP se ale bohužel začíná čím dál tím víc zamotávat, teď už je to opravdu totální bastl. Jediná cesta je nechat PHP za sebou a přejít na něco lepšího. Velmi mile by mě překvapilo, kdybychom se v příštím postu dozvěděli, že Nette je třeba v Javě :)

    před 11 lety
  4. Solvina #4

    avatar

    Davide, neni ti lito casu, ktery venujes zakoutim PHP a hackum, obchazeni a reseni trivialnich problemu, ktere ostatni jazyky nemaji?

    Chapu, ze si muzes doprat ten luxus a ve vlastni firme, na vlastnich projektech si veci resit po svem – jenze nezvladl bys v .Net, Jave, Ruby,… daleko vic nez v PHP? Totiz ze by ses mohl venovat praci vic nez vymysleni berlicek pro jazyk? (Ale zase chapu, ze te treba to osetrovani PHP anomalii v OOP pristupu bavi vic nez uceni se Jave ;-) ).

    před 11 lety | reagoval [17] David Grudl
  5. David Grudl http://davidgrudl.com #5

    avatar

    Něco pro pobavení. Hlavní vývojář Zend PHP Framework pan Mike Naberezny (slovanské jméno, že?) vysvětluje, jak obchází nedostatky při používání statických tříd:

    Call stack introspection almost solves this problem. I say almost because it relies on your storing your classes on disk in a specific way and looking at the filenames on the stack.

    Překlad: Analýza call stack těměř řeší problém. Říkám téměř, protože to závisí na speciálním způsobu ukládání tříd do souborů a dohledávání podle jména souboru ze zásobníku.

    To je vrchol zoufalství, jako když se snažíte palcem nohy opatrně odstranit mušku z oka.

    Zkoušel jsem to kdysi řešit takto, ale taky žádný zázrak.

    před 11 lety | reagoval [13] llook
  6. Věroš http://www.cestovatel.cz/~2/ #6

    Po Pythonu je poptávka třeba ze strany Seznamu či CZ.NICu, jednu dobu sháněl i Eurotel (některá verze jejich Webu byla v Zope). Ale Java či PHP jsou stále žádanější, než Python.

    Jinak souhlasím s tím, že Java se v životopisu vyjímá lépe a i s PHP budete žádanější než z Pythonem :(

    před 11 lety
  7. Jiří Bureš http://blog.converter.cz/ #7

    A zavládlo úplné zděšení…

    před 11 lety | reagoval [17] David Grudl
  8. pkm #8

    Vždycky přemýšlím, jak by vypadalo celé IT, kdyby se jazyky jako C, C++, Java, C# vyvíjely jako PHP. Možná by byl plat programátor trojnásobný :-)

    před 11 lety | reagoval [9] rarouš [12] hvge [17] David Grudl
  9. rarouš http://www.rarous.net #9

    avatar

    #8 pkme, to by bylo peklo

    před 11 lety
  10. Michal Hantl http://hantl.info #10

    #1 llooku, bude to Java, kdo nesouhlasí, ať se ozve:)

    před 11 lety
  11. hvge http://hvge.sk #11

    Nemozem si pomoct, oplati sa vobec prechadzat na PHP5? Mne z toho zatial vychadza vyhodnejsie pockat rovno na PHP6, preckat zopar zabugovanych prvotnych verzii a potom to „risknut“.

    Nepracujem na ultrasofistikovanych a rozsiahlych systemoch, takze veci ako private premenne a private metody ma az tak netrapia. S dobrou dokumentaciou, dobrou stabnou kulturou a premyslenym navrhom sa da podla mna docielit aj v PHP4 velmi vela.

    A na margo programatorov PHP a jazyka C, si to vystihol celkom pekne. Kedysi som zdrojaky PHP studoval (nebolo mi jasne, preco sa do built-in funkcii parametre kopiruju, namiesto predavania cez pointer). Bol som napriklad velmi zdeseny z rozsireneho makro balastu, takze novacik bez hlbsieho nahladu sa v kodoch lahko strati. Makra su skvela vec, usetria vela prace, ale co je vela, to je vela:)

    před 11 lety | reagoval [13] llook
  12. hvge http://hvge.sk #12

    #8 pkme, C a C++ ma za sebou tiez bohatu historiu. Dodnes je vidno v niektorych rozsirenejsich open source projektoch #ifdef hacky, riesiace kompatibilitu kompilatorov. Sam si pamatam na infarktove stavy v skole, kedy som si doma v linuxe porobil zadania a pri finalnom teste na skolskom Digital DECe, skoncili vsetky knizky. Vychytat len spravnu kombinaciu a poradie standardnych headrov, zabralo dobru hodinku. Aj to mi musel poradit spoluziak, ze problem je v standardnych headroch :)

    před 11 lety | reagoval [15] thingwath
  13. llook http://llook.wz.cz/weblog/ #13

    avatar

    #5 Davide Grudle, V PHP4 by se obešel i bez souborů, nechápu proč to měnili, viz http://llook.wz.cz/…-nazev-tridy

    #11 hvge, Podle mě hlavním argumentem po přechod na PHP5 je změna v předávání neproměnných referencí v PHP 4.4.x a 5.1.x.

    Přecejen je rozdíl mezi return new Trida; a $o = new Trida; return $o;. Nebo mezi funkce(new Trida); a funkce($o = new Trida);.

    Dopředně kompatibilní PHP4 tedy znamená buďto spoustu znepřehledňujících proměnných nebo spoustu zbytečně kopírovaných objektů.

    Za druhý největší argument pokládám podporu výjimek.

    před 11 lety | reagoval [14] hvge [17] David Grudl
  14. hvge http://hvge.sk #14

    #13 llooku, Pokial takychto operacii neurobis za beh skriptu 1000, alebo zrovna nekopirujes megabajtove pole, tak ti to moze byt jedno. Som velkym zastancom optimalizacie a efektivity, ale pri pomysleni na to, co vsetko sa robi pri obycajnom mysql_query, tak odpadaju akekolvek uvahy o zopar kilobajtoch alokovanych navyse. Pri jednom hite za sekundu ti to bude najskor jedno (server sa flaka), pri 100 hitoch a trvalej zatazi uz narazas na vzajomne sa blokujuce IO operacie, takze ti to bude jedno asi tiez :)

    před 11 lety
  15. thingwath #15

    avatar

    #12 hvge, Být pro PHP tolik interpretrů jako pro C kompilátorů… to by byla sranda nejmíň na druhou :-)

    před 11 lety | reagoval [16] hvge
  16. hvge http://hvge.sk #16

    #15 thingwathu, Áno to iste, to by bola skvelá cesta do digitálneho peklíčka :)

    před 11 lety
  17. David Grudl http://davidgrudl.com #17

    avatar

    #7 Jiří Bureši,

    A zavládlo úplné zděšení…

    Ty články jsem napsal po sobě kvůli objektivitě. Našlo se pár lidí, co zděší z ASP.NET chápalo jako blahořečení PHP. Nepochopitelně…

    #8 pkme,

    Vždycky přemýšlím, jak by vypadalo celé IT, kdyby se jazyky jako C, C++, Java, C# vyvíjely jako PHP.

    Přesně! Mé programátorské začátky byly spjaty s jazyky a překladači, které neměly chybu. Myslím to doslovně. Nebo snad víte o nějakém bugu v Turbo Pascalu či Assembleru?

    Dnes je nepochopitelně situace daleko horší. V mainstreamu nefunguje skoro nic, počínaje interpretací značkovacích jazyku (CSS, X/HTML) přes jazyky skriptovací (PHP), dokonce i ten Borland své Delphi zku..kazil.

    #13 llooku,

    V PHP4 by se obešel i bez souborů,

    odstranění tohoto hacku v PHP5 bylo poslední kapkou, pak musel přijít Zend Framework ;)

    #4 Solvino,

    Davide, neni ti lito casu, ktery venujes zakoutim PHP a hackum, obchazeni a reseni trivialnich problemu, ktere ostatni jazyky nemaji?

    Není, protože přesně vím, proč to dělám (vysvětlím třeba časem). Ale nemít důvod, tak se rozhlížím po jiných možnostech.

    před 11 lety
  18. Adam Hošek http://mamuf.webik.info/ #18

    avatar

    No, jak to říci a být současně slušný? :-)

    Po několika měsících zkušeností s Javou a prostředím NetBeans jsem se dostal opět k PHP. Když jsem kdysi přešel z PSPadu na Eclipse IDE + PHPeclipse, byl jsem nadšen. Spíš tedy kvůli možnostem IDE, než kvůli něčemu jinému. Dnes, po ochutnání lepšího ovoce, se v PHP cítím ztracený. Současná sofistikovaná IDE zpříjemňující vývoj v sofistikovaných programovacích jazycích mají sice podobný vliv jako povolení používat osobní kalkulátory na základních školách, ale chybějící kontrola téměř všeho tak, jak to znám z javovských IDE, mě v PHPeclipse trochu mátla.

    Na vině nejsou ani IDE, ani plugin PHPeclipse, jen rozdíly v jazycích a další drobnosti. V PHP ví pouze interpret, jaké třídy a rozhraní máte nebo nemáte k dispozici a jestli jste náhodou nezapomněli implementovat abstraktní metodu.

    Podivné pseudo-typování argumentů metod s určením typu (třídy) objektu jsem asi stále nepochopil a navíc je beztak k ničemu, když po přiřazení reference do objektové proměnné stejně „ztrácím“ kontrolu nad typem. Polymorfismus bez polymorfismu :-(. Asi to je syndrom z programování v Javě, viz. komentář k PHP5 Typehinting. Jenže zřejmě PHP5 Typehinting je jen jakási pomůcka, která zaručí, že dostanu objekt dané třídy, potomka dané třídy, nebo objekt, jehož třída implementuje dané rozhraní. Krom jiného, nelze takto předat hodnotu null.

    Aby toho nebylo málo, čtu ještě neduhy, o nichž píšeš Ty, Davide :-). Je to prostě sranda.

    Co se týče overloadingu, sám jsem byl překvapen podivnýcm chováním metody __toString(). Ta se zavolá jen a pouze v případě, kdy s objektem udělám toto:

    $foo = new MyClass();
    print $foo;
    echo $foo;

    Naopak tohle nefunguje:

    try {
          ...
    } catch (Exception $e) {
          echo "Mám, tě chybko... tady jsi: ".$e;
    }

    Proměnná $e se přeloží do řetězce zhruba jako Object id #2.

    před 11 lety | reagoval [19] llook
  19. llook http://llook.wz.cz/weblog/ #19

    avatar

    #18 Adame Hošku, Jo, typehinting je i podle mě zcela zbytečným prvkem jazyka. To samé by se bez něj docílilo takto:

    /**
     * @param Connection $db
     */
    function foo($db) {
        if (!($db instanceof Connection)) {
            trigger_error('$db musí být Connection!', E_USER_ERROR);
        }
    }

    Teda když už v tom jazyku je, tak to budu používat, ale jinak bych zrovna tuto věc (a pár dalších, včetně __toString) klidně oželel ve prospěch jiných věcí.

    před 11 lety
  20. johno http://johno.jsmf.net/ #20

    avatar

    Ja sa domnievam, že type hinting vymysleli hlavne kvôli Zend IDE, kde to údajne doplňuje metódy a tak. To, že do toho zapadli aj výnimky je možno skôr náhoda.

    Čo sa PHP IDE týka, tak veľmi dobré ohlasy som počul na ActiveState Komodo. Osobne by som však potreboval IDE pre PHP, ktoré má aspoň refaktoring.

    PHP je bastl, ale milujem ho.

    před 11 lety | reagoval [21] David Grudl
  21. David Grudl http://davidgrudl.com #21

    avatar

    #20 johno, IDE to umí přebírat z DocComment. Odsud získá i více informací, třeba typ návratové hodnoty nebo typ parametru, který není objekt (string, array apod.)

    PHP je bastl, ale milujem ho.

    :-)
    před 11 lety
  22. David Grudl http://davidgrudl.com #22

    avatar
    před 11 lety | reagoval [23] hvge [24] Adam Hošek
  23. hvge http://hvge.sk #23

    #22 Davide Grudle, Visual studio je u mna #1, za tych 100 dolarov sa to mozno aj oplati :)

    před 11 lety | reagoval [24] Adam Hošek
  24. Adam Hošek http://mamuf.webik.info/ #24

    avatar

    #23 hvge, Hm a nebo programovat v Javě, protože tohle jsou v NetBeans, příp. Eclipse, víceméně samozřejmosti :-). I přes to je tohle (#22 David Grudl) ale super, protože pamatovat si, jaké rozhraní má ta která třída nebo se stále přepínat do dokumentace je docela otrava.

    před 11 lety | reagoval [25] hvge
  25. hvge http://hvge.sk #25

    #24 Adame Hošku, To je skor vlastnost IDE, nie jazyka. Java sa da programovat tiez v notepade :) Ja navyse Visual Studio pouzivam v praci denne, takze pre mna to ma vcelku opodstatnenie :)

    před 11 lety | reagoval [28] Adam Hošek
  26. marau #26

    >Obyčejný Singleton si v PHP nenapíšete…
    A proč ne?
    Tohle snad nefunguje?

    class Singleton
    {
    
     static $handler;
    
     private function __construct() {}
    
     public static function handler()
     {
      if (!self::$handler) {
       self::$handler =& new Singleton;
      }
      return self::$handler;
     }
    
    }
    před 11 lety | reagoval [27] David Grudl [29] Adam Hošek
  27. David Grudl http://davidgrudl.com #27

    avatar

    #26 marau, to je zdání – zkus tuto třídu zdědit.

    před 11 lety | reagoval [28] Adam Hošek [30] Adam Hošek
  28. Adam Hošek http://mamuf.webik.info/ #28

    avatar

    #27 Davide Grudle, Ale to už pak není „obyčejný Singleton“, jestli se nepletu? Navíc Singleton je jen návrhový vzor a dědění „abstraktního“ Singletonu mi zabraňuje dědit něco docela jiného. Navíc si nejsem jistý, jak se chová privátní konstruktor, když třídu zdědím. Pokud si v dceřiné třídě založím vlastní konstruktor, obávám se, že jej mohu mít i veřejný, ne?

    #25 hvge, Samozřejmě, že tohle jsou vlastnosti IDE, psal jsem, že to jsou vlastnosti a chování v NetBeans IDE a Eclipse SDK.

    před 11 lety | reagoval [29] Adam Hošek
  29. Adam Hošek http://mamuf.webik.info/ #29

    avatar

    #28 Adame Hošku, V každém případě, když si k #26 marau přidám následující kód, výsledky jsou patrné. I když chybné chování self:: se projevuje také:

    class Extender extends Singleton {
        public function __construct() {}
    }
    
    //$s = new Singleton(); - causes an Fatal error
    $sh = Singleton::handler();
    $e = new Extender(); // toto projde bez potíží
    $eh = Extender::handler();
    echo (int)($e === $eh); // vypíše 0

    Testováno s PHP 5.1.2

    před 11 lety | reagoval [31] David Grudl [32] llook
  30. Adam Hošek http://mamuf.webik.info/ #30

    avatar

    #27 Davide Grudle,

    Tak už nevím kde, ale někdo tu psal, že PHP je vlastně špatné, ale přitom jej miluje. Mám pocit, že jsem na tom trochu obdobně. Určité vlastnosti PHP mám rád a jiné nesnáším.

    Ale co chci vlastně napsat – musím si ještě trochu rýpnout: v Javě mi IDE/překladač ani nepovolí dědit třídu s privátním konstruktorem.

    před 11 lety
  31. David Grudl http://davidgrudl.com #31

    avatar

    #29 Adame Hošku, Je samozřejmě potřeba, aby konstruktor byl protected, nikoliv private.

    Možná spíš než obyčejný Singleton si v PHP nenapíšete jsem měl napsat už i v případě obyčejného singletonu se projeví nedostatky PHP5. A lze je obejít buď rozkopírováním metody handler() do každé zděděné třídy nebo dodatečným předávání názvu třídy do této metody. V obojím případě duše objektového programátora trpí…

    před 11 lety | reagoval [32] llook
  32. llook http://llook.wz.cz/weblog/ #32

    avatar

    #31 Davide Grudle,

    rozkopírováním metody handler()

    A navíc použitím PHP4-like singletonu:

    public function getInstance() {
        static $instance;
        if (is_null($instance)) {
            $className = __CLASS__;
            $instance = new $className;
        }
        return $instance;
    }

    U toho #29 Adam Hošek totiž $sh === $eh a to i při předefinování metody i vlastnosti a to obvykle nechceme.

    Uvažuji, jestli nakonec není v PHP lepší singletony dělat nějak takhle:

    class Singletons {
        static public function getInstance($className) {
            static $instances = array();
            if (!isset($instances[$className])) {
                $instances[$className] = new $className;
            }
            return $instances[$className];
        }
    }
    před 11 lety | reagoval [33] johno
  33. johno http://johno.jsmf.net/ #33

    avatar

    Neviem si nejako živo predstaviť, kedy by som mal vytvárať zdedenú triedu zo Singletonu. Osobne mám singleton jeden. Volá sa Registry a v ňom sú všetky globálne objekty. Moc ich aj tak nie je.

    Singletons are evil.

    #32 llooku, Tá finta s __CLASS__ nemôže fungovať, lebo to je kúzelná konštanta, ktorá vracia meno triedy, v ktorej je metóda fyzicky napísaná a nie z ktorej je volaná.

    před 11 lety | reagoval [34] llook
  34. llook http://llook.wz.cz/weblog/ #34

    avatar

    #33 johno, Ta metoda getInstance() musí být rozkopírovaná do všech potomků. Jenže u toho příkladu v manuálu musí být navíc rozkopírovaná i ta statická vlastnost (a to při přehlédnutí může způsobit tak nenápadnou chybu, že i ten nejagilnější vývojář musí pustit debugger).

    Škoda, že standardně není nainstalovaný Runkit. Kdyby se dalo spolehnout na jeho podporu, tak by se rozkopírování metody mohlo dělat za běhu.

    před 11 lety
  35. johno http://johno.jsmf.net/ #35

    avatar

    Ta metoda getInstance() musí být rozkopírovaná do všech potomků.

    Aha. Tak to je taká istá prasárna ako kopírovať handler.

    před 11 lety | reagoval [36] llook
  36. llook http://llook.wz.cz/weblog/ #36

    avatar

    #35 johno, Skoro stejná. Akorát s handler musíš rozkopírovat i static $handler.

    před 11 lety
  37. wizard http://wizifoto.blogspot.com #37

    A z čeho jsi zděšen víc?

    před 11 lety

Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.