Špatně čitelný dokonalý kód

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

U českého překladu knihy Dokonalý kód místy dost trpím. Čas od času si musím dělat zpětný překlad do angličtiny, abych pochopil, co měl původní autor nejspíš na mysli. Hlavně se ale v ukázkách kódu míchají české identifikátory s anglickými – např. NextEmployee($zaměstnanec) je toho běžná ukázka, ale často se vyskytují i horší obraty – např. pět proměnných na stejné úrovni, z nich tři pojmenované česky a dvě anglicky. Jde o velmi častou chybu, tím spíš ale nechápu, že ji překladatel, korektor i editor v knize připustil. Já jsem si na to ve své knize dal pozor, v knize pojednávající o kvalitním kódu to je ale ještě důležitější.

Pozitivní nebo negativní podmínka?

Občas ale nesouhlasím ani s autorovými názory na to, jak má čitelný kód vypadat. Např. toto je ukázka kódu, který by údajně měl být dobře čitelný:

<?php
OpenFile($inputFile, $status);
if ($status == STATUS_SUCCESS) {
    RetrieveFile($inputFile, $fileData, $status);
    if ($status == STATUS_SUCCESS) {
        SummarizeFileData($fileData, $summaryData, $status);
        if ($status == STATUS_SUCCESS) {
            PrintSummary($summaryData);
            SaveSummary($summaryData, $status);
            if ($status == STATUS_SUCCESS) {
                UpdateAllAccounts();
                EraseUndoFile();
                $errorType = ERROR_TYPE_NONE;
            } else {
                $errorType = ERROR_TYPE_SUMMARY_SAVE_ERROR;
            }
        } else {
            $errorType = ERROR_TYPE_DATA_SUMMARY_ERROR;
        }
    } else {
        $errorType = ERROR_TYPE_FILE_READ_ERROR;
    }
} else {
    $errorType = ERROR_TYPE_FILE_OPEN_ERROR;
}
?>

Podle mě je tento kód čitelný velmi špatně. Kniha by měla upozornit na to, že mnohem lepší čitelnosti bychom v tomto případě dosáhli ošetřením chyb pomocí výjimek:

<?php
try {
    OpenFile($inputFile);
    RetrieveFile($inputFile, $fileData);
    SummarizeFileData($fileData, $summaryData);
    PrintSummary($summaryData);
    SaveSummary($summaryData);
    UpdateAllAccounts();
    EraseUndoFile();
    $errorType = ERROR_TYPE_NONE;
} catch (FileException $e) {
    $errorType = $e->getType();
}
?>

I když se ale budu soustředit na hlavní myšlenku, kterou se kniha původní ukázkou snažila předat (za if vždy uvádět pozitivní případ), tak s ní nesouhlasím. Spíše se totiž kloním k tomu za if uvádět kratší blok, což způsobí, že se na konci kódu (a velmi daleko za původní podmínkou) nehromadí řada klauzulí else, u kterých není na první pohled patrné, k jaké podmínce se vztahují.

Seznamy volání

Další ukázka „zčitelnění“ kódu na mě působí ještě hůř. Nejprve jak vypadal původní kód:

<?php
if ($inputCharacter < ' ') {
    $characterType = CHARACTER_TYPE_CONTROL_CHARACTER;
} elseif ($inputCharacter == ' '
    || $inputCharacter == ','
    || $inputCharacter == '.'
    || $inputCharacter == '!'
    || $inputCharacter == '('
    || $inputCharacter == ')'
    || $inputCharacter == ':'
    || $inputCharacter == ';'
    || $inputCharacter == '?'
    || $inputCharacter == '-'
) {
    $characterType = CHARACTER_TYPE_PUNCTUATION;
} elseif ('0' <= $inputCharacter && $inputCharacter <= '9') {
    $characterType = CHARACTER_TYPE_DIGIT;
} elseif (('a' <= $inputCharacter && $inputCharacter <= 'z') || ('A' <= $inputCharacter && $inputCharacter <= 'Z')) {
    $characterType = CHARACTER_TYPE_LETTER;
}
?>

A teď co s ním autor provedl, aby ho vylepšil:

<?php
function IsLetter($inputCharacter) {
    return ('a' <= $inputCharacter && $inputCharacter <= 'z') || ('A' <= $inputCharacter && $inputCharacter <= 'Z');
}

function IsPunctuation($inputCharacter) {
    return $inputCharacter == ' '
        || $inputCharacter == ','
        || $inputCharacter == '.'
        || $inputCharacter == '!'
        || $inputCharacter == '('
        || $inputCharacter == ')'
        || $inputCharacter == ':'
        || $inputCharacter == ';'
        || $inputCharacter == '?'
        || $inputCharacter == '-'
    ;
}

function IsDigit($inputCharacter) {
    return '0' <= $inputCharacter && $inputCharacter <= '9';
}

function IsControl($inputCharacter) {
    return $inputCharacter < ' ';
}

if (IsLetter($inputCharacter)) {
    $characterType = CHARACTER_TYPE_LETTER;
} elseif (IsPunctuation($inputCharacter)) {
    $characterType = CHARACTER_TYPE_PUNCTUATION;
} elseif (IsDigit($inputCharacter)) {
    $characterType = CHARACTER_TYPE_DIGIT;
} elseif (IsControl($inputCharacter)) {
    $characterType = CHARACTER_TYPE_CONTROL_CHARACTER;
}
?>

Na řídícím kódu mi nejvíc vadí ručně vyrobený seznam volání. Představte si, jak by kód vypadal, když bychom časem přidali dalších 10 druhů znaků. Vznikl by ještě delší seznam bez jakékoliv myšlenky a s nízkou informační hodnotou, který bychom museli ručně rozšiřovat. Vadí mi i určitá nekonzistence – proč se funkce jmenuje IsControl a konstanta CHARACTER_TYPE_CONTROL_CHARACTER?

Jak bych úlohu vyřešil já?

<?php
$characterTypes = array( // type => regexp character class
    CHARACTER_TYPE_LETTER => 'a-zA-Z',
    CHARACTER_TYPE_PUNCTUATION => ' ,.!():;?-',
    CHARACTER_TYPE_DIGIT => '0-9',
    CHARACTER_TYPE_CONTROL_CHARACTER => '\0-\x1F',
);
foreach ($characterTypes as $type => $regexp) {
    if (preg_match("(^[$regexp]\$)", $inputCharacter)) {
        $characterType = $type;
        break;
    }
}
?>

Řídící kód je trošku složitější, ale definice jednotlivých znaků je přehledná, snadno upravitelná a triviálně rozšiřitelná. Takže když bychom chtěli přidat další typ znaků, můžeme to udělat na jednom místě s minimální ruční prací.

Jakub Vrána, Dobře míněné rady, 15.7.2011, diskuse: 52 (nové: 0)

Diskuse

ikona Tomas Volf:

Tahle kniha nezni dobre, ale zkuste tuhle... je snadno k sehnani pres torrenty pokud ji chcete jenom prolistovat... http://www.amazon.com/Clean-Code-Handbook-…/0132350882

Tharos:

Odkazované knize dávám palec nahoru, dala mi toho dost. Ale knihu Dokonalý kód jsem nečetl, takže nemohu srovnat. Třeba by ani na odkazované nenechal Jakub nit suchou :).

root:

Autor knihy nepredpoklada, ze se pouzije jako programovaci jazyk php - oni totiz existuji i jazyky bez exceptions a bez regexpu ve standardni knihovne - proto by upraveny priklad s exceptions nesel napr. v jazyku C.

V druhem prikladu si myslim, ze slo hlavne o zabaleni nic nerikajicich podminek do logickych funkci, takze pri cteni slozite podminky je hned jasne o co jde.

Pokud se omezime na php tak nove navrzeny priklad s exceptions je prehlednejsi.

Pro programatora, ktery neovlada regexp je prehlednejsi serie ifu nez regexp.

ikona Jakub Vrána OpenID:

Série ifů je to, co mi v posledním příkladě vadí především. Kód bez jakékoliv myšlenky vzniklý metodou copy–paste.

Richard:

Root mi mluví z duše. To že první příklad není typický pro PHP je pro C je očividné. Druhý příklad je opět typicky z C. JV řešení bohužel toto vůbec nebere v potaz a také i v případě PHP je úplně pomíjen výsledný výkon takového "čitelného kódu".

ikona Jakub Vrána OpenID:

Na jazyku nezáleží. Na prvním příkladu mi vadí čtyři různě odsazené bloky else pod sebou, u kterých není na první pohled patrné, k čemu se vztahují. U druhého příkladu mi vadí ručně vytvořený seznam volání. Těchto obratů se chci zbavit těmi prostředky, které jazyk nabízí. V PHP to jde způsobem, který jsem popsal, v C by to šlo taky (i když trochu jinak).

NoxArt:

Tady s Jakubem se vším souhlasím

Kód takový že pro odsazení už je i začátek řádku málem mimo obrazovku opravdu není nic čitelného. Píšete že to v C nejde a přitom první příklad v něm jde úplně triviálně, stačí se nedržet dogmaticky pozitivnosti podmínky; druhý by šel taky

Tvá zmínka o výkonu je jen plácnutím - udělal jsem test 2. kódu a Jakubův je asi 50x rychlejší...

1. kód taky nemá důvod být pomalejší

Opravdový odborník :-):

Ad "Autor knihy nepredpoklada, ze se pouzije jako programovaci jazyk php - oni totiz existuji i jazyky bez exceptions"

Autor knihy hlavně dokáže udržet nit a věnovat se v jedné kapitole jednomu tématu. Jestliže kapitola má ukázat, že je dobré dodržovat nějaké konvence u if/else, nebudeme příklad přepisovat pomocí výjimek, protože pak by tam žádné if/else nebylo a příklad by pro danou kapitolu ztratil smysl. Je to asi jako kdyby tatínek učil Aničku jezdit na kole a přišel tam Pepíček a řekl, že můžou jet autobusem, a myslel si, jak na to vyzrál. Jistě, můžou jet rovnou autobusem, ale pak se nenaučí jezdit na kole. Potřebné je oboje - tak se jeden den učí na kole a až další den jezdit autobusem.

ikona Jakub Vrána OpenID:

Když je kód špatně navržen, kniha s názvem Dokonalý kód by na to v první řadě měla upozornit. Protože oprava řeší důsledek problému, nikoliv jeho příčinu. Teprve po tomto upozornění by se mohlo pokračovat ve výkladu řešení tohoto důsledku problému.

Ještě lepší by ale bylo zvolit vhodnější příklad, který nevychází ze špatného návrhu.

Co se toho držení nitě týče, tak to také není pravda. Ve stejné kapitole autor ukazuje, jak posloupnost ifů zaměnit za mocný VB Case (http://msdn.microsoft.com/en-us/library/cy37t14y.aspx). Upozornit u jiného příkladu, že by se za určitých okolností bez ifů dalo úplně obejít, by bylo na stejné úrovni.

Opravdový odborník :-):

Vy tu máte ve zvyku po lidech chtít ukázky kódu místo slovního vyjádření. Tak teď schválně zkuste napsat kód, který:
- Bude ilustrovat, že je dobré mít standardní chod programu v ifech a nestandardní/chybový v else větvích - a ne náhodně napřeskáčku.
- Bude srozumitelný i pro čtenáře bez znalosti kontextu (standardní knihovna nebo specifická syntaxe daného jazyka, objekty/proměnné vytvořené mimo rámec kódu, který se vešel do příkladu). Příklad bude jednoduše dávat smysl sám o sobě a bude zapsaný v pseudokódu případně v libovolném programovacím jazyce, ale tak, aby byl srozumitelný i tomu, kdo tento jazyk nezná.
- Bude dostatečně krátký - přibližně jako příklad v knize.

ikona Jakub Vrána OpenID:

Vzhledem k tomu, že s prvním bodem nesouhlasím, tak budu těžko psát ukázku, která ho podporuje.

Opravdový odborník :-):

Tak zkuste uvést příklad, kdy má smysl se řídit tou délkou bloků (kratší dávat dopředu)...

ikona Jakub Vrána OpenID:

Kniha doporučuje dva různé způsoby organizace ifů, které jdou často proti sobě (na což kniha upozorňuje):

1. Za then dávat standardní případ, za else neobvyklý.

2. V ifu používat kladnou podmínku, nikoliv negaci.

Já se neztotožňuji ani s jedním přístupem, protože za důležitější považuji blízkost if a else. Úzce to souvisí s tím, čemu kniha říká rozpětí proměnných.

Takže já bych do kapitoly o ifu dal třeba tenhle příklad:

<?php
if (strpos($input, ";") === false) {
    db_query($input);
} else {
    /*
    Tady bude parser, který najde středníky
    oddělující jednotlivé dotazy
    (a přeskočí ty, které jsou uvnitř řetězce).
    Vytvoří se pole $queries s jednotlivými dotazy.
    */
    foreach ($queries as $query) {
        db_query($query);
    }
}
?>

V tuto chvíli je úplně jedno, co bude nakonec na místě komentáře – může to být zavolání funkce, může to být regulární výraz, může to být několikařádkový parser. V ukázce bych nechal komentář.

Opravdový odborník :-):

Nevím, na jakém stroji pracujete vy, ale mně se tenhle kus kódu vejde na obrazovku více než třikrát. Je tedy celkem jedno, jestli to bude tak nebo onak - v obou případech vidím na první pohled obě větve. Navíc i bez jakékoli podpory IDE/editoru zde pomáhá odsazení a závorky, takže ztratit se v tom je nemožné (i pro pologramotnou opici). Je to o dost jiný případ než rozpětí proměnných (tam nám odsazení nepomáhá a jsme odkázání na zvýraznění syntaxe nebo prohledávání kódu - tam se pak hodí, když se všechny výskyty proměnné vejdou na jednu obrazovku resp. jsou blízko sebe).

Proto mají větší váhu ta první dvě pravidla a to vaše je až daleko za nimi. Smysl by mělo až ve chvíli, kdy se kód obou/všech větví nevejde najednou na obrazovku. Jenže v takovou chvíli už je chyba pravděpodobně někde jinde - kód by to chtělo tak jako tak zpřehlednit, z bloků udělat metody nebo jinak přeuspořádat.

Ještě viditelnější je to, když máte více podmínek vnořených do sebe (jako v tom příkladu z knihy). Při dodržení prvního pravidla, pak kód čteme přirozeně řádek po řádku* a tím sledujeme standardní/běžný chod programu. Nemusíme nahodile přeskakovat očima nahoru a dolů (jen kvůli tomu, že jeden blok byl o pár řádků kratší než jiný).

Mimochodem, co uděláte, když bude potřeba do jedné větve připsat (např. v rámci opravy chyby nebo implementace nového pořadavku) další kód a z kratší větve se tak stane delší a naopak? Přehodíte i jejich pořadí? Jak se to pak projeví ve verzovacím systému?

*) pouze přeskakujeme řádky s if podmínkami, které jen kontrolují, že jde všechno tak, jak má. Samozřejmě použití výjimek je přehlednější, v tom s vámi souhlasím, ale jsou jazyky/knihovny, které výjimky nemají/nepoužívají a kde je potřeba kontrolovat návratové kódy. Rovněž taky někdy výjimky nechceme použít, protože to nedává smysl - alternativní větev je určena např. chybějící hodnotou (null) nebo záporným číslem, nikoli vyhozenou výjimkou.

P.S. Přeji vám hodně štěstí v programování. Je vidět, že se o věcech snažíte přemýšlet, i když se často vydáváte slepými uličkami. To je dobře (tedy ta snaha). Až budete mít tolik let praxe jako já, tak taky hodně věcí budete vidět jinak.

Michal:

Jak tak čtu, tak se zde nedočkám jediného Vašeho komentáře bez již zmíněného podtextu. Viděl bych to tak, že si k tomu budeme každý myslet své a v diskusi to pomineme ?

Opravdový odborník :-):

Minule jste psal, že se vám líbí :-)

Ale co takhle diskutovat k věci - jak byste seřadil jednotlivé konvence 1) standardní chod programu v ifu, výjimečný/chybový v else 2) raději kladná podmínka než negace a přehozené větve 3) "metoda pan Vrána"

Michal:

Tedy,
Ad 1) Tato konvence mi nepřijde moc podstatná, navíc často mají obě větve podobnou důležitost.
Ad 2) Nezdá se mi, že by vždy kladná podmínka byla pochopitelnější, často právě ona negace je (pro mě) to podstatné.
Ad 3) Blízkost if a else za důležité považuji, protože rád vidím obě větve (i když vysokoúhlý display nemám a editor umí srolovávat bloky).
P.S. Knihu jsem si půjčil, takže už budu konkrétně vědět o čem je řeč.

ikona Jakub Vrána OpenID:

Zkusím to popsat ještě jinak. Následující fragment považuji za nepřehledný:

<?php
           
} else {
                $errorType = ERROR_TYPE_SUMMARY_SAVE_ERROR;
            }
        } else {
            $errorType = ERROR_TYPE_DATA_SUMMARY_ERROR;
        }
    } else {
        $errorType = ERROR_TYPE_FILE_READ_ERROR;
    }
} else {
    $errorType = ERROR_TYPE_FILE_OPEN_ERROR;
}
?>

Následující fragment mi přijde v pohodě:

<?php
           
}
        }
    }
}
?>

Opravdový odborník :-):

Omlouvám se, ale tenhle příklad nechápu. Kde se pak nachází standardní kód a kde ošetření chyb?

Michal:

Zdá se mi, že jste důvod těch fragmentů ale vůbec nepochopil.

Michal:

Asi tak.

Tomáš Fejfar:

Já jenom poznámku k překladu: pokud překládáš do pseudojazyka (tj. čeština pro angličana), tak si to nemůžeš sám jako autor (a prakticky ani jako původní nakladatel) ověřit. Ale pravda, že neschopnost překladatelů je občas do očí bijící. Ale jen aby to nebylo jako psal Franta Fuka s titulkama - máš na to týden, ne víc a ještě to dostaneš po částech :) Správně by se měl překaldatel "vyškolit" v konkrétní oblasti několik týdnů před překladem (resp. tak se to učí třeba teď na FFMU), ale to nikdo neuplatí ;) A lidi si to stejně koupí - člověk kterému překlady trhají oči si přečte radši originál ;)

ikona Jakub Vrána OpenID:

U překladů knih takový spěch nebývá – není příliš obvyklé, aby stejná kniha vyšla najednou v několika jazycích, takže k tomu ani není důvod.

Já jsem dělal korekturu překladu jedné knihy – to je myslím ideální postup. Překladatel s nějakým povědomím o dané oblasti knihu přeloží a pak ji dostane ještě expert se znalostí cílového jazyka, aby opravil technické nesmysly. U téhle knihy asi tu odbornou korektoru překladu přeskočili (alespoň nikdo takový není uveden v seznamu spolupracovníků).

Opravdový odborník :-):

Co se týče pořadí těch if/else větví - jsou dvě taková dvě doporučení:

1) standardní chod programu v ifu, nestandardní (výjimečný, chybový) v elsu.

2) testovat raději rovnost než nerovnost: if (a == b) { … } else { … } se bude číst lépe, přirozeněji než totéž s nerovností a přehozenými větvemi.

Tahle dvě pravidla jdou někdy proti sobě, pak je to víceméně na citu (někdo dává striktně přednost 1.)

Ale řešit délku těch bloků mi, slušně řečeno, nepřijde moc rozumné… když už se to "nevejde na obrazovku" a člověk se v tom ztrácí, tak obvykle stojí za to si ty bloky pojmenovat, udělat z nich metody. To je zase nějaký váš svérázný způsob "programování".

Ostatně autor té knihy to radí u toho IsLetter, IsDigit atd. - a právě na to byl ten příklad zaměřený - cílem bylo ukázat, že se delší bloky vyplatí vyčlenit do metod/funkcí. Proto je dost ubohé ho osočovat z toho, že to šlo udělat lépe a má to vlastně úplně blbě - že to jde udělat pomocí tabulek, jistě - ale na to je tam celá kapitola (Metody řízené tabulkami). V této kapitole bylo cílem ukázat ty metody, takže kdyby se to udělalo přes tabulku, ten příklad bude k ničemu. Nepředbíhejte :-) Ale jinak chválím, že tu knihu čtete, třeba vám to pomůže.

David Grudl:

Klučík, co dělá 30 let v Javě, chválí Jakuba, cheche…

Michal:

To jsi neměl psát hele, dopadne to jako na zdrojaku :-)

Opravdový odborník :-):

Ohledně těch třiceti let jsem vám odpovídal už minule...

Vás bych možná taky pochválil, bohužel není za co - k tématu diskuse jste zatím nijak nepřispěl. Co si myslíte o uspořádání if/else větví? Jaké jsou vaše priority a konvence?

ikona Jakub Vrána OpenID:

Bylo by možné tu odpověď odkázat nebo zopakovat? Mě by vysvětlení taky zajímalo.

Opravdový odborník :-):

Věta: "Ohledně těch třiceti let jsem *vám* odpovídal už *minule*" určuje místo dostatečně jednoznačně. Navíc si myslím, že větší radost z toho budete mít, když to najdete sám :-)

P.S. proč tady nefungují ani základní HTML značky? Stačily by odkazy, tučné, kurzíva a odrážky. Jednou jsem tu chtěl vložit odkaz na jiný komentář #d-12441 ale nešlo to.

ikona Jakub Vrána OpenID:

Místo to jednoznačně neurčuje. Nevím, jestli „vám“ mířilo na Davida Grudla, na všechny diskutující, nebo snad na mě (i když příspěvek na mě nereaguje). Taky z toho není poznat, jestli šla odpověď veřejně nebo třeba e-mailem.

Opravdu nevím, co je složitého na tom uvést jeden odkaz nebo citaci.

Podporovaný formát příspěvku je jednoznačně uveden před formulářem pro jeho vložení. Stačí si to přečíst. HTML značky nejsou podporované, protože mi to tak vyhovuje. Odkaz vytvořit jde, dokonce ještě intuitivněji než přes HTML značku a opět podle popisu.

Opravdový odborník :-):

"Vám" = David Grudl. A bylo to na tomto blogu. To už snad najdete, ne?

ikona Jakub Vrána OpenID:

Zkusíme to tedy jinak. Jaká je vaše skutečná praxe, že se považujete za odborníka? Z vašeho projevu se totiž nic takového vyvodit nedá.

Např. příspěvkem http://php.vrana.cz/spatne-citelny-dokonaly-kod.php#d-12440 jste totiž předvedl pravý opak odborného přístupu: O 100% funkčním řešení jste prohlásil, že „nemůže fungovat“. Po žádosti, ať si doplníte znalosti, jste dál trval na svém řešení, které naopak bezchybně nefunguje. A když jste konečně nejspíš pochopil, jak velkého omylu jste se dopustil, tak jste místo uznání vlastní chyby prohlásil, že už oponenta nebudete dál ztrapňovat.

To je pravý opak odborného přístupu. Opravdový odborník si totiž nejdřív nastuduje oblast, ke které se vyjadřuje. Když si ji nastuduje špatně a je vyzván k doplnění znalostí, tak to učiní. A když udělá chybu, tak ji uzná a dá za pravdu oponentovi.

ikona Opravdový odborník :-):

Argumenty došly, hra skončila, máte pravdu. Uznávám svou chybu a zanechávám tímto svého trapného vystupování zde a i na jiných serverech.

Máte mé svolení pročistit zdejší diskuze od mých příspěvků a tím navrátit jejich informační hodnotu na tradičně velmi dobrou úroveň.

ikona Filip Procházka:

Opravodový "Opravdový odborník :-)" by se tak snadno nevzdal :)

David Grudl:

Hurá!

maryo:

Ja si tu knihu chtel taky precist kdyz jsem videl na kolik mistech ji chvali... Ale tohle se mi teda taky vubec nelibi. Nicmene tem regularum bych se v tomhle pripade vyhnul. Asi bych to resil nejakym polem metod/objektu nebo neco na ten zpusob...

Opravdový odborník :-):

Tím se nenechte znepokojit. Podívejte se třeba na hodnocení a recenze na Amazonu. Kniha je to dobrá a stojí za přečtení. Byť samozřejmě není dokonalá (ale 100% bezchybnou knihu jsem ještě neviděl), taky se mi tam některé věci nelíbí… Ale inteligentní člověk si z knihy vezme to dobré a posune ho to někam dál - a hlupák v ní bude hledat chyby a honit si na nich ego.

Michal:

Pokud dobře čtu, tak Jakub nepíše o tom, že tento "přístup" je chybný, ale špatně čitelný a navrhl jiná řešení, která si pokud možno udržují svoji čitelnost při dalším rozšíření.
Btw. líbí se mi ten rýpací podtext v každém Vašem příspěvku (nic proti Vám).

ikona Jakub Vrána OpenID:

S tím souhlasím. Kniha za přečtení rozhodně stojí, i když některé věci bych udělal jinak (jako programátor) nebo napsal jinak (jako autor).

Opravdový odborník :-):

Ještě taková "drobnost". Učili vás ve škole rozdíl mezi předávání hodnotou a předávání odkazem?

Ten váš příklad:

<?php
OpenFile
($inputFile, $status);
...
?>

nemůže fungovat. Jestliže totiž předáte $status takto, funkce ho nemůže změnit, protože byl předán jako hodnota - funkce ho změní jen ve svém kontextu, ale ten následující if ($status == STATUS_SUCCESS) tu změněnou hodnotu "neuvidí" - $status bude pořád stejný jako před zavoláním funkce, takže pravděpodobně nedefinovaná hodnota.

Aby ten váš příklad fungoval, je potřeba předávat parametry odkazem - to se v PHP dělá pomocí & - např.

<?php
OpenFile
($inputFile, &$status);
?>

Pak se skutečně změní $status i v kontextu volajícího kódu a kontrola v ifu bude dávat smysl.

ikona Jakub Vrána OpenID:

Přestaňte se prosím ztrapňovat a nejprve si doplňte znalosti. http://www.php.net/manual/en/functions.arguments.….by-reference

Vámi doporučený způsob je navíc od PHP 5 zastaralý. http://www.php.net/manual/en/ini.core.php#…-pass-reference

Opravdový odborník :-):

Místo nadávání ten příklad raději opravte, ať to neplete lidi. Ten $status můžete z funkce dostat i jako návratovou hodnotu, když se vám nelíbí &.

Každopádně bych řekl, že je lepší zastaralá syntaxe než nefunkční kód, ne?

Zkuste si odkomentovat a pustit obě varianty:

<?php

function fx ($p) {
    $p = "tuto hodnotu jsme nastavili uvnitř funkce";
}

$a = "hodnota před voláním funkce";

// Předávání hodnotou
// fx($a);

// Předávání odkazem
// fx(&$a);

echo($a);
echo(
"\n");
?>

php --version
PHP 5.3.3

A pokud jste to myslel tak, že by & měl být v deklaraci funkce, měl jste její deklaraci uvést:

<?php
function fx (&$p) {
    ...
}
?>

Myslete na to, že příklad by měl dávat smysl sám o sobě - různé implicitní předpoklady, vedou pouze ke snížení srozumitelnosti a k nedorozuměním.

NoxArt:

Proč mi přijde, že ve své snaze co nejvíc zkritizovat už se do toho celého motáte?

1) Zmíněná ukázka je přece z knihy - ne od JV - a zde nikde implementace funkcí nejsou - a nejsou ani nijak pro danou věc podstatné ... *kdosi* tu napsal "Autor knihy hlavně dokáže udržet nit a věnovat se v jedné kapitole jednomu tématu"

2) Vaše uvedená syntaxe je zastaralá a nepoužívá se, regulérní a *funkční* syntaxe je & v deklaraci (proč není uvedeno viz (1))

Souhlasím - už se prosím neztrapňujte

ikona Jakub Vrána OpenID:

Za prvé nikomu nenadávám. Příspěvkem jste se ztrapnil, protože poučujete ostatní, aniž byste se v problematice sám orientoval. Pouze jsem vás tedy požádal, ať s tím přestanete a nejprve si doplníte znalosti, což jste bohužel neudělal.

Příklad funguje, není co opravovat. Samozřejmě předpokládá (stejně jako původní příklad v knize), že proměnná $status je předávána referencí. To je na první pohled jasné každému, kdo umí v PHP programovat.

Direktiva allow_call_time_pass_reference je nejen zastaralá, ale brzy bude dokonce odstraněna. Vámi navržený kód by pak přestal fungovat úplně.

Opravdový odborník :-):

Dobře, už vás nebudu ztrapňovat :-)

Jen bych rád viděl tuto <a href="#d-12441">ukázku kódu</a>.

Lukyer:

Pan "OPravdovy odbornik" si bohuzel plete Ccko s PHP :) V C je samozrejme predavani adresy promenne do funkce naprosto normalni a je to jedina moznost (krom returnu), ovsem od c++ a ve vsech vyssich jazycich je prave mozno pouzivat i "zjednodusenou" alternativu, kdy se v deklaraci funkce vyjmenuji parametry, ktere budou predavany odkazem, prave pomoci "&".

Michal:

Taky taková "drobnost".
<?php
OpenFile
($inputFile, $status);
?>
Toto vychází z původního kódu knihy, v Jakubově verzi to tak není.

Opravdový odborník :-):

Původní kód v knize je ale v jiném programovacím jazyce - když to přepisuji do jiného jazyka, tak bych to měl přepsat tak, aby to v něm fungovalo, ne?

Michal:

Knihu Dokonalý kód jsem nečetl, takže budiž, ale přeci jen bych raději diskutoval na téma tohoto článku.

Opravdový odborník :-):

To já taky. Zajímal by mne třeba příklad, kdy se vyplatí uspořádat větve if/else podle délky jednotlivých bloků a ne podle logické podstaty.

Lukyer:

Rekl bych, ze tato kniha pojednava o uplne jinem jazyce a uplne jinem pristupu ... hadam ze se jedna o ciste Ccko, kde jsou tyto obraty naprosto bezne. Porovnavani ascii hodnoty znaku na rozlisovani, rucni "vyjmenovavani" seznamu znaku povolenych/zakazanych/atd, zadne foreach kontstrukce, zadne in_array, pouzivani konstant namisto "magic number", zadne zachytavanij vyjimek, atd. Pokud tedy opravdu utrzky kodu z knihy patri jazyku C (necetl jsem), myslim, ze je vse naprosto v poradku.

ikona Jakub Vrána OpenID:

Kniha je na jazyce nezávislá, asi nejvíc ukázek je ve Visual Basicu, potom v C++ a dost i v Javě. Občas se ale zmiňují i jazyky jako Python nebo ADA. Kupříkladu výjimky se v určitých částech knihy používají zcela rutinně.

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

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