Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM    Subskrybuj kanał ATOM dla tagu php Kanał ATOM (tag: php)

Autor wpisu: Tomasz Kowalczyk, dodany: 17.04.2011 21:56, tagi: javascript, jquery, php

Nie znam biblioteki, która bardziej podbiłaby serca programistów stron internetowych niż jQuery właśnie. Wielu ją polubiło od pierwszej linijki kodu, wielu nienawidzi, chociaż nie zna. Nie zmienia to jednak faktu, że projekt rozpoczęty przez Johna Resiga okazał się być strzałem w dziesiątkę, rozwiązującym setki problemów związanych z różnicami w implementacji silników JavaScriptu w przeglądarkach internetowych. [...]

Autor wpisu: Śpiechu, dodany: 16.04.2011 19:16, tagi: php, mysql

Ostatnio mnie ostro zjechaliście. Dzięki za komentarze, szczególnie te negatywne (yyy wszystkie?). Wszystkie starannie przeczytałem. Poczytałem co nieco i zdecydowałem się uderzyć z tematem jeszcze raz. Tym razem uwzględniając zadania takie jak „a co jak będę miał kilka serwerów: testowy, produkcyjny, itp.”, „a co jak chcę połączyć się z dwiema bazami na raz”?

Punktem wyjścia stał się Twittee, czyli kontener stworzony w 2009 r. przez Fabiena Potenciera zajmujący 140 znaków (tyle żeby całość dała się przesłać w postaci pojedynczej wiadomości w serwisie Twitter). Podstawą kontenera jest magia __set() i __get(), czyli to co Zyx lubi najbardziej :-) Całość została przeze mnie mocno zmodyfikowana. Dodałem np. rzucanie wyjątkami jeżeli wymagana wartość nie została ustawiona plus obsługę domknięć w przypadku gdy ustawiona wartość jest funkcją anonimową.

Parę linijek dotyczących ustawienia PDO wcisnąłem do funkcji anonimowej plus dodałem możliwość trzymania pojedynczej instancji PDO w razie potrzeby (zwrócę potem uwagę na static w domknięciu). Obiekt PDO „nie wie”, że jest w kontenerze i dobrze. Istotą DI jest to żeby klas nie trzeba było specjalnie dostosowywać do współpracy z kontenerem.

Obsługę wyjątków w całości zrzucam na klientów nie mieszając kompetencji kontenera, który ma ustawiać/zwracać zmienne/fabrykować obiekty.

class DBContainer {
 
  protected $values = array();
 
  public function __construct() {
        $this->loadDefaults();
  }
 
  protected function loadDefaults() {
    $this->pdo_driver = 'mysql';
    $this->pdo_host = 'localhost';
    $this->pdo_dbname = 'nazwabazy';
    $this->pdo_user = 'user';
    $this->pdo_pass = 'haslo';
    $this->pdo_charset = 'SET NAMES utf8';
    $this->pdo_persist = false;
 
    $this->pdo_getpdo = function(DBContainer $cont) {
 
      // static w kontekscie funkcji anonimowej
      static $persistentPDO;
 
      $pdoCreator = function() use ($cont) {
        if (!extension_loaded('PDO')) throw new Exception('Brak modulu PDO');
        $pdo = new PDO(
                    $cont->pdo_driver . ':host=' . $cont->pdo_host . ';dbname=' . $cont->pdo_dbname,
                    $cont->pdo_user,
                    $cont->pdo_pass,
                    array(PDO::MYSQL_ATTR_INIT_COMMAND => $cont->pdo_charset));
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
        return $pdo;
      };
 
      if ($cont->pdo_persist && $persistentPDO instanceof PDO) {
        return $persistentPDO;
      }
      elseif ($cont->pdo_persist) {
        $persistentPDO = $pdoCreator();
        return $persistentPDO;
      }
      else {
        return $pdoCreator();
      }
    };
 
    public function __set($key,$val) {
        $this->values[$key] = $val;
    }
 
    public function __get($key) {
        if (!isset($this->values[$key])) {
            throw new Exception("Wartosc {$key} nie istnieje");
        }
        if ($this->values[$key] instanceof Closure) {
            return $this->values[$key]($this);
        }
        else {
            return $this->values[$key];
        }
    }
}

Przykłady użycia:

$c = new DBContainer();
 
// PDO na domyslnych ustawieniach
$pdo = $c->pdo_getpdo;
 
// przestawiam baze danych
$c->pdo_dbname = 'testowa baza';
$nowePDOdlaBazyTestowa = $c->pdo_getpdo;
 
// znowu przestawiam baze danych, przestawiam na zapis PDO na stale
$c->pdo_dbname = 'baza produkcyjna';
$c->pdo_persist = true;
 
// sprawdzam czy na pewno obiekty PDO sa tej samej instancji
echo spl_object_hash($c->pdo_getpdo) . '<br>' . spl_object_hash($c->pdo_getpdo);
// zwroci taki sam hash

Na raz następny pokażę jak można fajnie korzystać z tego dla obiektów korzystających z pdo wewnętrznie.

Osoby nielubiące magii uprasza się o powstrzymanie od wylewania żalu. Po to zrobili __get(), __set() i dynamiczne typy zmiennych żeby z nich korzystać. Dobra dokumentacja wg mnie załatwia sprawę.

Autor wpisu: sokzzuka, dodany: 16.04.2011 10:38, tagi: php

Jakiś czas temu, zainspirowany artykułem Giorgio Sironiego - „How to remove getters and setters” rozpocząłem dyskusję na forum goldenline na temat przydatności getterów i setterów. Dyskusja była dość burzliwa, jak to zawsze ma miejsce, gdy próbuje się naruszać dogmaty. Jednak wszystko przebiegło w na tyle przyjaznej atmosferze, że nie skończyło się na „flejmłorze” i padło kilka interesujących argumentów. Teraz nadszedł czas by z perspektywy czasu podsumować tą dyskusje i przedstawić wnioski, do jakich doszedłem po jej zakończeniu. Dla tych, którym się nie chce czytać artykułu, szybki szkic problematyki – Giorgio wysunął śmiałą tezę, że stosowanie „getterów i setterów” psuje enkapsulację, która jest jedną z podstaw programowania zorientowanego obiektowo. W swoim artykule opisuje on sposoby na całkowite pozbycie się tych często używanych artefaktów.

Jako, że zgadzam się z główną tezą artykułu Giorgia, w dalszej części artykułu zamierzam zaprezentować przypadki w których użycie getterów bądź setterów jest szkodliwe, wraz z uzasadnieniem i przykładowym rozwiązaniem problemu. Pokaże również, przypadki w których zastosowanie tych konstrukcji ma sens. Abyśmy się jednak dobrze zrozumieli, najpierw moja definicja – czym są gettery i settery.

Jako getter i setter, rozumiem metody klasy, zwykle nazwane wg wzoru „getFoo()”, „setFoo()”, które  ”mapują się 1:1″ z odpowiadającymi im polami klasy. Przykład:

class Bar {

    private $_foo;

    public getFoo(){
        return $this->_foo;
    }

    public setFoo($foo){
        $this->_foo = $foo;
    }

}

Przypadki problematyczne:

1.Setter, który wpływa na obiekty kolaborujące klasy.

Wyobraźmy sobie, że mamy sobie taką oto klasę do obsługi tabeli w bazie danych:

class Foo_Table {

    private $_db;

    public function setDb($db){
        $this->_db = $db;
    }

    public function getDb(){
        return $this->_db;
    }

    public function fetchAll(){
        //kod
    }

}

Przypomina ona z grubsza klase Zend_Db_Table_Abstract i jest to właściwe skojarzenie (różnica polega na obecności statycznego settera). . Zobaczmy teraz jakie problemy generuje zastosowanie settera:

//gdzies w kodzie tworzymy obiekt $fooTable
$db1 = new PDO($dsn, $username, $passwd, $options);

$fooTable = new Foo_Table;
$fooTable->setDb($db1);

//inne miejsce w kodzie
$fooTable->fetchAll(); //zwraca array(1,2,3);

//inne miejsce w kodzie
$db2 = new PDO($dsn2, $username, $password,$options);
$fooTable->setDb($db2);

//inne miejsce w kodzie
$fooTable->fetchAll(); //zwraca array(4,5,6) - inna baza danych

Jak widać na wyżej załączonym kodzie, z powodu zastosowania settera, można w międzyczasie zmienić obiekt adaptera bazy danych, z którego korzysta klasa tabeli. Konsekwencją tego jest mniejsza przewidywalność klasy – w drugim przypadku dostajemy inny wynik. W przypadku Zend_Db_Table_Abstract sytuację pogarsza fakt, zastosowania statycznego settera, co wielokrotnie zwiększa możliwości zmiany adaptera i nieprzewidywalność takiego kodu. Łatwo usunąć ten problem poprzez likwidację settera i zastosowanie wstrzykiwania obiektu połączenia z bazą danych poprzez konstruktor.

2. Rozpełzanie się kodu

Dziwna nazwa, ale już tłumacze o co chodzi. Zostawmy na chwilę poprzedni przykład z tabelą, żeby nie było, że przyczepiłem się do Zend_Db. Kolejnym przykładem będzie klasa reprezentująca użytkownika, oczywiście dla potrzeb przykładu została skrócona do minimum:

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Tomasz Kowalczyk, dodany: 15.04.2011 05:16, tagi: php

W komentarzu do wpisu o flagach bitowych zostałem poproszony przez jednego z komentujących, Bartosza Wójcika, o opisanie obsługi wartości typu DWORD w PHP. Wychodząc naprzeciw tej prośbie, rozbiłem temat na pewnego rodzaju wprowadzenie we wpisie o odczytywaniu wartości bajtów w zmiennych liczbowych, a dzisiaj podejmuję temat właściwy. Zapraszam do lektury, a także zgłaszania własnych pomysłów [...]

Autor wpisu: Aiv, dodany: 15.04.2011 00:42, tagi: php

Z bazy zaległych syfów wyciągnąłem taki oto kodzik:Continue reading: Ataki na web aplikacje – cz. 4

Autor wpisu: Aiv, dodany: 14.04.2011 23:05, tagi: php

Następna mutacja kodu z części 2 tej serii wpisów.Continue reading: Ataki na web aplikacje – cz. 3

Autor wpisu: Aiv, dodany: 14.04.2011 22:54, tagi: php

Kolejny kwiatek znaleziony na końcu każdego pliku PHP w audytowanej stronie www:Continue reading: Ataki na web aplikacje – cz. 2
Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.