Rozwój:Kodowanie

Z MoodleDocs
(Przekierowano z Kodowanie)
Skocz do:nawigacja, szukaj

Każdy wspólnie opracowywany projekt potrzebuje spójności i stabilności, aby być silny.

Poniższe wytyczne kodowania muszą być przestrzegane, aby osiągnąć ten cel. Prawdą jest, że niektóre starsze fragmenty kodu odbiegają od nich w niektórych aspektach, jednak ostatecznie zostaną poprawione. Nowy kod powinien spełniać poniższe wymogi w jak największym stopniu.

Ogólne zasady

  1. Wszystkie pliki z kodem powinny używać rozszerzenia .php.
  2. Wszystkie pliki z szablonami powinny mieć rozszerzenie .html.
  3. Wszystkie pliki tekstowe powinny używać formatu tekstu w stylu Uniksa (większość edytorów posiada taką opcję).
  4. Wszystkie tagi php muszą być "pełne": <?php ?> ..., a nie "krótkie" <? ?>.
  5. Wszystkie istniejące noty prawne muszą być zachowane. W razie konieczności możesz dodać własne.
  6. Każdy plik powinien dołączać (require_once) główny plik config.php.
  7. Każde inne wywołanie include/require powinno używać bezwzględnej ścieżki, zaczynającej się od $CFG->dirroot lub $CFG->libdir. Dołączanie według relatywnej ścieżki czasem zachowuje się dziwnie w PHP.
  8. Każdy plik powinien sprawdzić, czy użytkownik został właściwie uwierzytelniony, używając require_login() oraz has_capability() lub require_capability().
  9. Każdy dostęp do bazy danych powinien być realizowany za pomocą funkcji z pliku lib/dmllib.php kiedy tylko to możliwe - takie podejście zapewnia kompatybilność pomiędzy różnymi bazami danych. Jak się pewnie przekonasz, prawie wszystko jest możliwe do zrobienia za pomocą tych funkcji. Jeśli musisz napisać kod SQL, upewnij się, że jest on: przenośny, ograniczony do kilku określonych funkcji w twoim kodzie (zazwyczaj plik lib.php) i wyraźnie oznaczony.
  10. Nie twórz i nie używaj globalnych zmiennych z wyjątkiem standardowych $CFG, $SESSION, $THEME, $SITE, $COURSE i $USER.
  11. Wszystkie zmienne powinny być zainicjalizowane albo przynajmniej powinna być sprawdzona ich obecność przez isset() lub empty() przed ich użyciem.
  12. Wszystkie napisy powinny nadawać się do tłumaczenia - twórz nowe teksty w plikach "lang/en_utf8", nadając im zwięzłe nazwy małymi literami w języku angielskim. Możesz je potem pobrać za pomocą get_string() i print_string(). Nigdy nie usuwaj napisów (fraz) aby zapewnić wsteczną kompatybilność.
  13. Wszystkie błędy powinny być wyświetlane, używając print_error(). Dzięki temu poprawia się tłumaczenie i pomoc dla użytkowników (pojawiają się hiperłącza do stron dokumentacji na wiki).
  14. Wszystkie pliki pomocy powinny nadawać się do tłumaczenia - twórz nowe teksty w katalogu "lang/en_utf8/help" i wywołuj je przez helpbutton(). Jeśli musisz uaktualnić plik pomocy:
    • o małą zmianę (gdzie stare tłumaczenie tekstu nadal jest sensowne), to zrobienie tej zmiany jest dopuszczalne, pod warunkiem, że poinformujesz translation AT moodle DOT org.
    • o dużą zmianę, to powinieneś utworzyć nowy plik, dodając kolejną liczbę na końcu jego nazwy (np. nazwapliku2.html). Dzięki temu tłumacze będą mogli łatwo zauważyć, że pojawiła się nowa wersja pliku. Oczywiście kod i indeks pomocy powinny również zostać uaktualnione, aby wskazywały na najnowsze wersje.
  15. Dane przychodzące od przeglądarki (wysłane przez GET lub POST) są modyfikowane przez dodanie "magicznych cudzysłowów" (niezależnie od ustawień PHP). W związku z tym możesz bezpiecznie wsadzić je bezpośrednio do bazy danych. Inne dane (z plików, baz danych) muszą zostać eskejpowane za pomocą addslashes() przed dodaniem ich do bazy danych. To zagadnienie często przysparza problemów. Więcej o eskejpowaniu na osobnej stronie.
  16. BARDZO WAŻNE: Wszystkie teksty wewnątrz Moodle, a szczególnie te, które pochodzą od użytkowników powinny być wyświetlane za pomocą funkcji format_text(). Zapewnia to odpowiednią filtrację i oczyszczenie tekstu. Więcej informacji na stronie o funkcjach wyjściowych.
  17. Aktywność użytkowników powinna być logowana za pomocą funkcji add_to_log(). Logi te są używane przy raportach aktywności i logach.
  18. Tworząc łącza HTML, zawsze dbaj o to, aby ścieżka była podana względem głównego katalogu całej witryny, np. $CFG->wwwroot/mod/blonk/view.php?id=99 zamiast view.php?id=99. Dzięki temu twój kod będzie działał, kiedy zostanie wywołany przez skrypt znajdujący się w innym katalogu.

Styl kodowania

Wiemy, że zmienianie twojego stylu kodowania, do którego jesteś przyzwyczajony, może być irytujące. Jednak wyobraź sobie irytację ludzi, którzy w przyszłości będą męczyć się z kodem napisanym niespójnym stylem. Oczywiście każdy styl kodowania ma swoje dobre i złe strony, ale aktualny styl jest obowiązujący, więc prosimy o jego przestrzeganie.

1. Wcięcia powinny być dokonywane czterema spacjami. W OGÓLE nie używaj znaków tabulacji.

2. Nazwy zmiennych zawsze powinny być łatwymi do odczytania, znaczącymi angielskimi słowami, pisanymi małymi literami. Jeśli potrzebujesz więcej niż jednego słowa, po prostu zestaw je wszystkie razem, jednak staraj się je utrzymać tak krótkie, jak to tylko możliwe. Używaj liczby mnogiej dla tablic obiektów.

     DOBRZE: $quiz
     DOBRZE: $errorstring
     DOBRZE: $assignments (dla tablicy obiektów)
     DOBRZE: $i (tylko w małych pętlach)
     ŹLE: $Quiz
     ŹLE: $aReallyLongVariableNameWithoutAGoodReason
     ŹLE: $error_string

Stałe powinny zawsze być pisane wielkimi literami i zawsze zaczynać się nazwą modułu. Słowa składowe powinny być odseparowane od siebie znakami podkreślenia.

     define("FORUM_MODE_FLATOLDEST", 1);

4. Nazwy funkcji powinny być prostymi angielskimi słowami, pisanymi małymi literami oraz zaczynać się nazwą modułu, aby uniknąć konfliktów pomiędzy modułami. Słowa powinny być oddzielone znakami podkreślenia. Parametry powinny mieć rozsądne wartości domyślne, kiedy tylko to możliwe. Zawuaż, że nie ma odstępu pomiędzy nazwą funkcji a następującymi po niej nawiasami.

     function forum_set_display_mode($mode=0) {
         global $USER, $CFG;
         
         if ($mode) {
             $USER->mode = $mode;
         } else if (empty($USER->mode)) {
             $USER->mode = $CFG->forum_displaymode;
         }
     }

5. Bloki powinny zawsze być zawierane w nawiasach klamrowych (nawet, gdy w bloku jest tylko jedna linia). Moodle używa tego stylu:

     if ($quiz->attempts) {
         if ($numattempts > $quiz->attempts) {
             error($strtoomanyattempts, "view.php?id=$cm->id");
         }
     }

6. Napisy powinny być definiowane, używając pojedynczych cudzysłowów gdzie tylko jest to możliwe. W ten sposób oszczędzamy pamięć.

     $var = 'pewien tekst bez żadnych zmiennych';
     $var = 'ze specjalnymi znakami, np. końca linii '."\n";
     $var = 'bardzo długi napis z '.$pojedyncza.' zmienną w środku';
     $var = 'pewien '.$tekst.' z '.$wieloma.' zmiennymi w '.$srodku.' niego';

7. Komentarze powinny być dodawane tak często, jak jest to użyteczne, aby wyjaśnić przepływ programu oraz przeznaczenie funkcji czy też zmiennych.

  • Każda funkcja (i klasa) powinna używać popularnego formatu phpDoc. Pozwala to na automatyczne generowanie dokumentacji.
  • Komentarze jednoliniowe powinny być w stylu //, wyrównane tak, aby pasować do otaczającego kodu.
     /**
     * Na początku powinien znaleźć się opis, z gwiazdkami dokładnie jak
     * w tym przykładzie. Jeśli chcesz odwołać się do innej funkcji,
     * zrób to w ten sposób: {@link clean_param()}. Następnie dodaj opisy
     * każdego parametru jak poniżej.
     *
     * @param int $postid Nazwa zmiennej jest poprzedzana przez typ PHP
     * @param array $scale Nazwa zmiennej jest poprzedzana przez typ PHP
     * @param array $ratings Nazwa zmiennej jest poprzedzana przez typ PHP
     * @return mixed
     */
     function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {
         if (!$ratings) {
             $ratings = array();     // Initialize the empty array
             if ($rates = get_records("forum_ratings", "post", $postid)) {
                 // Process each rating in turn
                 foreach ($rates as $rate) {
     ....etc

8. Spacje powinny być często używane - nie bój się "rozstrzelić" tesktu aby zyskać na przejrzystości. Pojedynczy odstęp powinien znaleźć się pomiędzy nawiasami a normalnymi wyrażeniami, ale nie powinno być odstępu pomiędzy nawiasami, a nazwami funkcji:


     foreach ($objects as $key => $thing) {
         process($thing);
     }
     
     if ($x == $y) {
         $a = $b;
     } else if ($x == $z) {
         $a = $c;
     } else {
         $a = $d;
     }

9. Tworząc KOPIĘ obiektu, zawsze używaj funkcji clone() z php5 (inaczej możesz utworzyć wyłącznie referencję do poprzedniego obiektu). Moodle zadba, aby ten sposób zadziałał również z php4.

     DOBRZE:  $b = $a;
     ŹLE:     $b = clone($a);

Jeśli to, co chcesz skopiować nie jest obiektem, ale może zawierać obiekty (np. tablica obiektów) użyj fullclone().

Struktury bazy danych

Aby ułatwić ci tworzenie tabel zgodnie z poniższymi wytycznymi, zalecamy używanie wbudowanego edytora definicji bazy danych (XMLDB).

  1. Każda tabela musi mieć automatycznie inkrementowane pole id (INT10) ustawione jako indeks podstawowy (zobacz IdColumnReasons).
  2. Główna tabela zawierająca instancje każdego modułu musi mieć taką samą nazwę, jak ma moduł (np. widget) i zawierać następujące pola:
    • id - opisano wyżej
    • course - id kursu, do którego należy każda instancja
    • name - pełna nazwa każdej instancji modułu
  3. Inne tabele powiązane z modułem, zawierającym informacje o "rzeczach" (ang. things) powinny być nazwane widget_things (w liczbie mnogiej).
  4. Nazwy tabeli i kolumn nie powinny zawierać słów zarezerwowanych dla baz danych. Sprawdź ich listę przed nazywaniem tabel i kolumn.
  5. Nazwy kolumn powinny zawsze być pisane małymi literami, krótkie i proste. To samo dotyczy nazw zmiennych.
  6. Jeśli to tylko możliwe, kolumny zawierające referencje do pola id innej tabeli (np. widget) powinny być nazwane widgetid. (To nowa konwencja i nie jest przestrzegana w niektórych starszych tabelach.)
  7. Pola boolowskie powinny być zaimplementowane jako pola małych liczb całkowitych (np. INT4) i zawierać wartości 0 lub 1. To umożliwi dalsze poszerzanie zakresu wartości, jeśli kiedyś zajdzie taka konieczność.
  8. Większość tabeli powinna zawierać pole timemodified (INT10), każdorazowo uaktualniane bieżącym znacznikiem czasu (zwracanym przez funkcję time() w PHP).
  9. Zawsze definiuj rozsądne domyślne wartości dla każdego pola.
  10. Nazwa każdej tabeli powinna zaczynać się prefiksem bazy danych ($CFG->prefix). W wielu przypadkach dzieje się to automatycznie. W przypadku Postgres dotyczy to także nazwy każdego indeksu.
  11. Aby zapewnić kompatybilność między bazami dostosuj się do poniższych reguł dot. słowa kluczowego AS (oczywiście tylko wtedy, kiedy potrzebujesz aliasów na tabele lub kolumny):
    • Nie używaj słowa kluczowego AS dla aliasów tabel.
    • Używaj słowa kluczowego AS dla aliasów kolumn.
  12. Nigdy nie twórz unikalnych kluczy (UNIQUE KEY). Zamiast tego użyj UNIQUE INDEX. Być może w przyszłości zdecydujemy się wprowadzić spójność (wzajemność) odwołań w Moodle. Wtedy może się okazać, że potrzebujemy UNIQUE KEY, ale jeszcze nie teraz. Zauważ, że edytor XMLDB pozwala na określenie zarówno wyłącznej dla XMLDB reguły UNIQUE jak i FOREIGN, ale tylko podległe INDEXy zostaną wygenerowane.
  13. Wspomniane unikalne klucze (UNIQUE KEY, tylko w XMLDB) muszą być zdefiniowane tylko wtedy, gdy dane pole/pola będą celem odwołania jakiegoś FOREIGN KEY (również tylko w XMLDB). W przeciwnym wypadku utwórz UNIQUE INDEX zamiast UNIQUE KEY.
  14. Nazwy tabel powiązanych z jednym blokiem muszą trzymać się następującej konwencji: $CFG->prefix + "block_" + nazwa_bloku + cos_jeszcze. Przykładowo, przyjmując, że $CFG->prefix jest "mdl_", to nazwy wszystkich tabel bloku "rss_client" muszą zaczynać się od "mdl_block_rss_client" (można dodać więcej słów na końcu, np. "mdl_block_rss_client_innatabela...). Ta reguła zostanie wymuszona wraz z nadejściem Moodle 2.0. Developerzy będą mieli czas na wprowadzenie koniecznych zmian do tego czasu. Więcej informacji w Task 6786.
  15. Nigdy nie modyfikuj baz danych w gałęziach stabilnych. Inaczej użytkownikom uaktualniającym jedną wersję stabilną do drugiej zmiany zostaną wprowadzony podwójnie. To może być przyczyną poważnych błędów.
  16. Odwołując się do zmiennej całkowitoliczbowej w zapytaniach SQL, nie umieszczaj wartości w cudzysłowiach. Na przykład poprawne jest get_records_select('question', "category=$catid"), ale get_records_select('question', "category='$catid'") już nie. Drugi przykład ukrywa błędy powodowane niezdefiniowanym $catid. (Ten wątek wyjaśnia wszystko.)

Kwestie bezpieczeństwa, formularze i dane w URL

  1. Nie polegaj na "register_globals". Każda zmienna musi być poprawnie zainicjalizowana w każdym pliku z kodem. Musi być jasne, skąd ona pochodzi.
  2. Inicjalizuj wszystkie tablice i obiekty, nawet jeśli są puste. $a = array() lub $obj = new stdClass();.
  3. Nie używaj funkcji optional_variable(). Jest przestarzała i została zastąpiona przez optional_param(). Dobierz wartość PARAM_XXXX odpowiednią dla oczekiwanego typu danych.
  4. Nie używaj funkcji require_variable(). Jest przestarzała i została zastąpiona przez required_param(). Dobierz wartość PARAM_XXXX odpowiednią dla oczekiwanego typu danych.
  5. Ostrożnie użwaj data_submitted(). Dane muszą być przygotowane (oczyszczone) przed użyciem.
  6. Nie używaj $_GET, $_POST ani $_REQUEST. Użyj required_param() lub optional_param() zależnie od swoich potrzeb.
  7. Nie używaj if (isset($_GET['coś'])) i podobnych konstrukcji, aby sprawdzić, czy coś jest ustawione i używane. Zamiast tego zastosuj $cokolwiek = optional_param( 'cokolwiek',-1,PARAM_INT ) a następnie sprawdź, czy otrzymana wartość mieści się w oczekiwanym zakresie, np. if ($cokolwiek >= 0) {...
  8. Jeśli to możliwe, zgrupuj wszystkie wywołania required_param() i optional_param() na początku pliku. Tak samo postępuj z inicjalizacją innych zmiennych. Takie podejście ułatwia ich odszukanie.
  9. Użyj mechanizmu "sesskey" aby zabezpieczyć formularze przed próbami ataków. Prosty przykład użycia: w kodzie generującym formularz umieść następującą linijkę: <input type="hidden" name="sesskey" value="<?php echo sesskey(); ?>" />. W trakcie przetwarzania danych z formularza sprawdź sesskey za pomocą if (!confirm_sesskey()) {error('Zły klucz sesji (session key)');}.
  10. Wszystkie nazwy plików muszą być oczyszczane za pomocą funkcji clean_filename(), jeśli nie zostało to wcześniej dokonane przez prawidłowe wywołanie required_param() lub optional_param().
  11. Wszystkie dane czytane z bazy danych muszą zostać zmodyfikowane przez addslashes() przed ich powtórnym zapisaniem do bazy. Cały obiekt danych może być zmieniony na raz, przez użycie addslashes_object().
  12. Jeśli tylko jest to możliwe, dane które będą zapisywane do bazy, muszą pochodzić z formularzy używających method="POST". Dane GET (z URL) nie nadają się do zapisania w bazie.
  13. W trosce o przenośność kodu, powinieneś unikać czerpania danych z $_SERVER.
  14. Upewnij się, że dane zapisywane do bazy są przetwarzane przez funkcję clean_param(), wywołaną z odpowiednim PARAM_XXXX.
  15. Jeśli piszesz własny kod SQL, upewnij się, że jest on poprawny. W szczególności uważaj na brakujące cudzysłowy wokół wartości. Możliwy atak typu SQL injection.
  16. Wszystkie dane sprawdzaj przed użyciem (szczególnie te zapisywane do bazy). Nie licz na to, że ktoś zrobił to za ciebie wcześniej.
  17. Bloki kodu powinny zwierać pełną strukturę PHP (deklaracja klasy, definicje funkcji, itd.) - proste, samodzielne bloki kodu zwiększają szansę na użycie niezainicjalizowanej zmiennej.