• Strona główna
  • Curriculum Vitae
  • O mnie
  • Przykład: Gramatyka w PHP
  • Przykład: Kompresja CSS
  • Przykład: Kompresja JavaScript
  • Przykład: Skracanie linków
  • Przykład: Wykrywanie serwera HTTP
  • Przykład: Własna bramka SMS
  • Mapa strony
  • Kontakt
Niebieski Pomarańczowy Zielony Różowy Fioletowy

jQuery.extends dla PHP

Opublikowane 23 marca 2011. Autor: Kamil Brenk. Wizyt: 2 684.

Kategorie: PHP
Tematyka: JavaScript, jQuery w praktyce, PHP, praktyczne skrypty

mar 23

Każdy kto używał jQuery i tworzył pod niego pluginy to zdążył już zapoznać się z genialną metodą $.extends służącą w głównej mierze do łączenia kilku obiektów z nadpisywaniem istniejących już metod / własności.

Najczęstszym wykorzystaniem niniejszej metody jest łączenie dwóch obiektów:

  • z domyślnymi parametrami danego obiektu,
  • z ustawieniami zdefiniowanymi przez użytkownika.

Najlepiej i najłatwiej będzie jednak posłużyć się przykładem:

1
2
3
4
5
6
7
8
9
10
11
12
var pluginOptions = {
    validate: false,
    limit: 5,
    name: "foo"
};

var userOptions = {
    validate: true,
    name: "bar"
};

jQuery.extend(pluginOptions, userOptions);

Co tutaj się dzieje? A więc najpierw ustawiamy domyślne parametry pluginu – własności konfiguracyjne, które później podstawiamy w odpowiednich miejscach w tworzonej klasie.

Następnie pobieramy obiekt z własnościami webdevelopera wykorzystującego nasz plugin. Obiekt ten nadpisuje domyślne ustawienia i teraz w pluginie są wykorzystywane ustawienia przekazane przez developera.

To tyle. Choć metoda $.extend() ma więcej możliwości, skupmy się na wyżej opisanych.

Przenosimy $.extends do PHP

Metoda tak bardzo mi się spodobała, że postanowiłem wykorzystywać niniejszą funkcjonalność w PHP.

Nie widziałem wbudowanej funkcji mającej podobne działanie (no może poza array_merge, ale jest drobna różnica w działaniu), więc stworzyłem własny kod, który prezentuje poniżej:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * Array Extends
 * merge the contents of two array together into the first array
 *
 * @param array     default options
 * @param array     user options
 *
 * @return array    new options
**/

function arrayExtends($default, $options) {

    foreach ($options as $key => $value) {
   
        if (is_array($value)) {
            $default[$key] = arrayExtends($default[$key], $value);
        } else {
            $default[$key] = $value;
        }
           
    }

    return $default;
   
}

W powyższym kodzie wykorzystałem rekurencję aby podmiana wartości w tablicach działała także w zagnieżdżonych tablicach.

Poza tym, istotną różnicą między PHP a JavaScript jest typ danych, na których operujemy. W jQuery bowiem do metody trafiały obiekty, natomiast w PHP operujemy na tablicach asocjacyjnych.

Praktyczny przykład użycia

I teraz czas na krótki przykład z życia wzięty:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// default options
$defaults = array(
    'font-size'     => 15,
    'color'         => array(0, 0, 0),
    'pos-x'         => 0,
    'pos-y'         => 20
);

// user options
$options = array(
    'font-size'     => 25,
    'color'         => array(255, 255, 255)
);
       
$o = arrayExtends($defaults, $options);

W wyniku powyższej fuzji dwóch tablic powstanie następująca tablica wynikowa:

1
2
3
4
5
6
$o = array(
    'font-size'     => 25,
    'color'         => array(255, 255, 255),
    'pos-x'         => 0,
    'pos-y'         => 20
);
Uzasadnienie

I to by było na tyle. Ten sposób jest bardzo prosty w użyciu oraz przyjemny w późniejszym czytaniu kodu, przynajmniej tak mi się wydaje.

Jeśli masz inne sposoby lub przemyślenia odnośnie tworzenia domyślnych ustawień dla klasy wraz z późniejszym ich nadpisywaniem/wykorzystaniem to z chęcią poczytam o tym w komentarzach :-)

Komentarze (15)

  1. activ 23 marca 2011

    http://pl.php.net/array_merge

  2. singles 23 marca 2011

    Ten kod Ci się uruchamia? Bo jak dla mnie, to extends jest na liście reserved words w PHP. I mi się nie uruchamia. A zrobiłem porównanie z array_merge, i Twój kod rzeczywiście działa lepiej dla zagnieżdżonych struktur :)

  3. Kamil Brenk 23 marca 2011

    @activ: fajnie, że przeczytałeś wpis.

    @singles: faktycznie, dzięki za zwrócenie uwagi :-) U siebie mam tą funkcję zapisaną jako metodę o trochę innej nazwie, przy pisaniu bloga nie chciałem komplikować niepotrzebnie sprawy i zmieniłem – już poprawione.

  4. Michał Śliwka 23 marca 2011

    Przydało by się aby przykład pokazywał tą „drobną różnicę w działaniu” pomiędzy Twoją funkcją a array_merge. Wiem o co chodzi oczywiście, ale przykład tego nie obrazuje.
    Mało tego przy założeniach z przykładu równie dobrze można użyć:

    1
    $o = array_merge($defaults, $options);

    jak i

    1
    $o = $options + $defaults;

    i obydwa sposoby będą wydajniejsze od Twojej funkcji i wydaje mi się że bardziej czytelne (Przynajmniej w projektach o dużej ilości kodu).

  5. Jacek Smolak 23 marca 2011

    @Kamil Brenk
    Hmm… a po co robić coś, co już jest i działa :)

    1
    2
    $p = $options + $defaults;
    print_r($p);

    I masz ten sam wynik co w przypadku Twojej funkcji.

    Pozdrawiam!

  6. Michał Śliwka 23 marca 2011

    @Jacek Smolak
    Nie do końca działa :) Kamilowi chodziło o coś innego tylko posłużył się trochę słabym przykładem (który nie do końca obrazuje przyświecającą jago funkcji ideę).
    Aby szybko zobrazować o co chodzi zmień sobie tablicę $options na np. taką:

    1
    2
    3
    4
    $options = array(
        'font-size'     => 25,
        'color'         => array(255)
    );
  7. Jacek Smolak 23 marca 2011

    @Michał Śliwka
    Tak, w tym przypadku tak. Bazowałem na danych w przykładzie.

    Pozdrawiam!

  8. Michal Wachowski 23 marca 2011

    merge the contents of two objects together into the first object

    1
    $o = arrayExtends((object) $defaults, (object) $options);

    Oj bo chyba nie :)

    Odpowiednij $.extends w prototype.js Object.extend()

    I na koniec, moja wersja PHP’owego odpowiednika

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    function merge(&$target, $source) {
       $source = func_get_args();

       for($i = 1; $i < func_num_args(); $i++) {
           foreach($source[$i] as $key => $srcValue) {
               if(is_object($target)) {
                   $trgValue = &$target->$key;
               }
               else {
                   $trgValue = &$target[$key];
               }


               if(is_array($srcValue)) {
                   $trgValue = merge($trgValue, $srcValue);
               }
               else {
                   $trgValue = $srcValue;
               }
           }
       }

       return $target;
    }

    $targets = (object) array(
       'font-size'     => 15,
       'color'         => array(0, 0, 0),
       'pos-x'         => 0,
       'pos-y'         => 20
    );

    // user options
    $source = (object) array(
       'font-size'     => 25,
       'color'         => array(255, 255, 255)
    );

    // more user options
    $moreOptions = (object) array(
       'color'         => array(128),
       'pos-x'         => 20,
       'pos-y'         => 20
    );

    $o = merge($targets, $source, $moreOptions);
    /*
    stdClass Object
    (
       [font-size] => 25
       [color] => Array
           (
               [0] => 128
               [1] => 255
               [2] => 255
           )

       [pos-x] => 20
       [pos-y] => 20
    )
    */
  9. Kamil Brenk 23 marca 2011

    Eh, na potrzeby bloga chciałem zminimalizować kod i wywalić niepotrzebne fajerwerki i doszedłem do tego stopnia, że śmiało można dać:

    1
    $o = $defaults + $options;

    Oczywiście nie o takie działanie funkcji mi chodziło i już wyjaśniam zasadę działania oryginału. Mamy taką tablicę domyślnych wartości:

    1
    2
    3
    4
    $defaults = array(
        'table' => 'teksty',
        'columns' => array('tytul', 'tekst', 'status'),
    );

    Następnie przekazujemy takie dane do nadpisania:

    1
    2
    3
    4
    $options = array(
        'table' => 'teksty',
        'columns' => array('meta_keywords', 'meta_description'),
    );

    W wyniku dodawania tablic uzyskalibyśmy następującą tablicę:

    1
    2
    3
    4
    array(
        'table' => 'teksty',
        'columns' => array('meta_keywords', 'meta_description', 'status'),
    );

    Co nie jest prawidłowym wynikiem w przypadku, gdy później pobieramy dane z ‚columns’ i robimy coś z nimi (np. wyświetlamy z bazy takowe kolumny).

    Było jeszcze kilka opcji, na które nie zwróciłem uwagi we wpisie – bardziej chodziło mi o samą ideę dostarczania i pobierania danych konfiguracyjnych klasy :-)

  10. Kamil Brenk 23 marca 2011

    @Michał: że też musisz czytać komentarze do funkcji :P poprawione.

  11. eRIZ 24 marca 2011

    Dla mnie to trochę mało intuicyjne, gdyż pozostaje mały problem – co w wypadku, gdy chcemy nadpisać któryś parametr, bez łączenia subtablic?

  12. Kamil Brenk 24 marca 2011

    @eRIZ: racja racja, nie jest to zbyt bogata funkcja, bardziej chodziło mi o samą ideę konfigurowania klasy, coś na wzór jquery.extends (którą to konstrukcję bardzo lubię wykorzystywać).

  13. Michal Wachowski 24 marca 2011

    @eRiz – dla pojedynczej wartości nie ma sens używać tej funkcji, dla większej ilości – już tak.

  14. Adam Brodziak 24 marca 2011

    Późno już, ale czy tak nie działa array_replace_recursive()?

  15. Michal Wachowski 24 marca 2011

    A działa, pod warunkiem że pracujesz na 5.3.



Kamil Brenk Blog

PHP, JavaScript, SQL, HTML

  • Informacje o blogu

    Kamil Brenk

    Blog o tworzeniu aplikacji na potrzeby sieci Web.

    Praktyczne przykłady, porady i sztuczki. PHP, SQL, AJAX, JavaScript, HTML i pochodne.

    Kanał RSS

    • Najnowsze
    • Komentarze
    • Popularne
    • Liczniki w CSS
    • Wyprzedaż książek o programowaniu!
    • Niestandardowy placeholder
    • JavaScript w modułach
    • Co dalej z blogiem?
    • Interaktywna mapa w HTML i CSS
    • Olsztyn: Jak wyseparować zawartość zassaną przez file_get_content?
    • ERMLAB: Od czegoś trzeba zacząć :) Wiele osób właśnie stawia na...
    • david: co nalezy wkleić na stronę aby plik ze stylami był ladowany...
    • krynicz: Nie jestem pewien czy dobrze to rozumiem: wpisujemy OG w...
    • yaro: Jak zmienić re_write znak "_" na "-"?
    • Piotr: stworzyłem prostą stronkę w PHP, czy jest możliwość aby...
    • MichalR: Super sprawa... bardzo przydatne.. dzieki i pozdrawiam..
    • Niestandardowe czcionki na stronie
    • Sposoby wczytywania JavaScript
    • Gramatyka w PHP, część 1
    • Umowa i zaliczka dla freelancera
    • Wysyłanie wiadomości SMS w PHP
    • Projekt aplikacji po stronie klienta
    • Własny mechanizm Feed
  • Szukajka
    Wpisz co chcesz wyszukać na stronie…
  • Kategorie
    • Apache
    • Freelancer
    • Front-end Development
    • HTML5 & CSS3
    • Inne
    • JavaScript
    • Książki
    • PHP
    • Po godzinach
    • Pozycjonowanie
    • Protokół HTTP
    • SQL
    • Wyrażenia regularne
  • Moje serwisy
    • Testy zawodowe
    • Miłość, uczucia i seks
  • Czytane blogi
    • Wojciech Sznapka
    • Wojciech Soczyński
    • Michał Wachowski
    • Tomasz Kowalczyk
    • Filip Górczyński
  • Strona główna
  • Curriculum Vitae
  • O mnie
  • Przykład: Gramatyka w PHP
  • Przykład: Kompresja CSS
  • Przykład: Kompresja JavaScript
  • Przykład: Skracanie linków
  • Przykład: Wykrywanie serwera HTTP
  • Przykład: Własna bramka SMS
  • Mapa strony
  • Kontakt

Kamil Brenk © 2010. All rights reserved.

Designed by FTL Wordpress Themes brought to you by Smashing Magazine.

Do góry ∧