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

Autor wpisu: sokzzuka, dodany: 22.06.2010 00:29, tagi: php

Do napisania tego postu zainspirował mnie artykuł na 97 rzeczy pt. Stosuj zasady programowania funkcjonalnego. Każdemu polecam przeczytanie go aby dowiedział się dlaczego należy stosować te zasady. Ja w tym poście będę chciał pokrótce przedstawić jak rady zawarte w artykule można odnieść do kodu w PHP i jakie korzyści odniesiemy stosując refaktoring poszczególnych rodzajów kodu. Duchem całego programowania funkcjonalnego jest przezroczystość referencyjna – funkcja dla tych samych danych zwraca konsekwentnie ten sam wynik, aby tak było kod musi spełniać kilka zasad:

Pierwsza zasadą jest unikanie globalnego stanu. Często można natknąć się w skryptach na następujące konstrukcje „popełniane” przez początkujących:

$conn = mysql_connect();
 
function fetch_users(){
global $conn;
/**
reszta kodu
**/
}

Problem z tego rodzaju kodem jest taki, że jest on całkowicie nieprzewidywalny. Jeżeli zamkniemy gdzieś w naszym skrypcie zamkniemy połączenie do bazy, a potem wywołamy funkcję fetch_users, po prostu dostaniemy błąd. Oprócz tego, osoba postronna czytająca kod, w zasadzie nie jest w stanie wywnioskować co powinno znaleźć się w zmiennej $conn.

Są dwa rozwiązania refaktoringu takiego kodu, pierwszy:

$conn = mysql_connect();
 
function fetch_users($connection){
/**
kod
*/
}

Drugi:

class DbService {
    protected $_conn;
    public function __construct(){
       $this->_conn = mysql_connect();
    }
 
    public function fetch_users(){
         /** kod **/
    }
 
    public function __destruct(){
         mysql_close($this->_conn);
    }
}

Dzięki refaktoringowi nr.1 zyskaliśmy większą przewidywalność funkcji i czytelność. Dzięki refaktoringowi nr.2 uzyskaliśmy przewidywalność, abstrakcje i enkapsulacje.

Przykładem pogwałcenia tej zasady jest również wzorzec singleton (namiętnie używany w ZF) i rejestr.

class FooController extends Zend_Controller_Action {
 
    function barAction(){
        $baz = Zend_Registry->getInstance()->baz;
        // czym jest baz ???
    }
 
}

Jak widzimy powyżej, gdybyśmy recenzowali taki kod, nie jesteśmy bez uruchamiania skryptu w stanie stwierdzić, jakiego typu jest zmienna $baz, co więcej nie jesteśmy w stanie stwierdzić czy rejestr przechowuje coś pod tą zmienną. Refaktoring:

class FooController extends Zend_Controller_Action {
 
    function barAction(ModelUser $baz){
        $aList = $baz->getList();
        // baz jest instancją ModelUser, wiemy jakie ma metody i musi istnieć żeby ta metoda mogła być //wywołana 
    }
 
}

Oczywiście osobną kwestią jest jak wstrzyknąć zależności do kontrolera, ja bym zastosował do tego kontener IOC, ale to osobna bajka.

Drugą zasadą jest nieprzekazywanie przez referencję do funkcji:

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

Autor wpisu: Zyx, dodany: 21.06.2010 18:23, tagi: php

Nazwanie jednej klasy obserwatorem, a drugiej obserwowanym nie daje nam jeszcze wzorca "Obserwator". Z tym zgodzą się chyba wszyscy. Gdy identyczną zasadę spróbujemy zastosować do MVC, wywołamy wielką wojnę z argumentami kalibru "nie rozumiesz idei wzorców projektowych". Kursów MVC jest w sieci na pęczki, problem polega jednak na tym, że opisują one w rzeczywistości zupełnie inny wzorzec, niż twierdzą jego autorzy. W tym wpisie pragnę pokazać jego prawdziwe oblicze oraz zaprezentować eksperymentalną implementację, którą rozwijam od jakiegoś czasu.

Autor wpisu: sokzzuka, dodany: 21.06.2010 09:08, tagi: php

Kolejna porcja nowości z wewnętrznej grupy dyskusyjnej deweloperów Php. Tym razem tematem przewodnim jest APC czyli Alternative PHP Cache. Dla przypomnienia powiem tylko, że APC jest rozszerzeniem do Php dzięki któremu bez zmian w kodzie można przyśpieszyć swoje skrypty o 300-400%. Dzieje się tak dzięki temu, że APC zachowuje w pamięci skompilowaną postać skryptu po pierwszym wykonaniu i przy każdym następnym uruchomieniu skrypt nie musi być od nowa parsowany.

Jeden z deweloperów zaproponował defaultowe dołączenie APC do dystrybucji Php i zintegrowanie jego kodu z kodem języka (trunkiem). Ten ruch był już uzgodniony i miało to zostać zrealizowane przy okazji tworzenia Php6. Niestety nie ma już Php6, powstała więc propozycja aby w najbliższej wersji (5.4 ?) przeprowadzić to połączenie.

Doszło do dyskusji i okazało się, że część osób nie chce takiego połączenia. Jako powody wymieniali m.in to, że trudny błąd w APC może zastopować wydawanie kolejnych wersji języka, oraz to, że istnieją również inne rozszerzenia alternatywne do APC i nieuczciwym było by promować tylko wybrane.

Natomiast zwolennicy tego rozwiązania argumentowali, że dołączenie APC nie jest przeszkodą dla używania alternatywnych rozszerzeń, poza tym dzięki temu, że będzie rozwijane w corze, będzie pod większą uwagą deweloperów.

Nasuwa się jeszcze jeden plus w integracji – APC będzie rozprowadzane w standardowej dystrybucji i dzięki temu każdy będzie mógł korzystać z przyśpieszenia bez oglądania się na hosterów czy mają zainstalowane odpowiednie rozszerzenie.

Koniec końców wyłoniły się trzy możliwe rozwiązania:

  • zintegrować i domyślnie wyłączyć
  • zintegrować i domyślnie włączyć
  • nie integrować

Ja popieram opcje nr.1 a jakie jest Wasze zdanie ?

Autor wpisu: Zyx, dodany: 19.06.2010 14:36, tagi: php

Niektóre systemy bazodanowe takie, jak np. PostgreSQL wspierają koncepcję dziedziczenia tabel. Pozwala ona nie tylko na współdzielenie części deklaracji przez dwie tabele, ale także danych, co znacząco ułatwia realizację niektórych zadań. Choć biblioteka Doctrine obsługuje dziedziczenie od jakiegoś czasu, działało ono na zasadzie emulacji, co oczywiście jest marnotrawstwem, jeśli korzystamy z systemu, który wspiera tę funkcjonalność natywnie.

Autor wpisu: sokzzuka, dodany: 17.06.2010 23:08, tagi: php

Część z Was pewnie wie o istnieniu listy dyskusyjnej php.internals. Jest to lista na której to core developerzy PHP rozmawiają o zmianach w języku. Jako, że praktycznie codziennie odwiedzam ową listę, postanowiłem co jakiś czas pisać post o aktualnych dyskusjach na niej oraz zapytać Was czyli społeczność o zdanie w poruszanych tam kwestiach. Ostatnio najświeższym tematem na tapecie jest usunięcie z głównej dystrybucji PHP rozszerzenia SQLite w wersji 2 na rzecz wersji 3.

Proponenci argumentują konieczność usunięcia tego rozszerzenia tym, że biblioteka (i baza) SQLite w wersji 2 nie jest już rozwijana i trzymanie tego kodu w głównej dystrybucji jest bez sensu.

Przy okazji dyskusji kilka osób zaproponowało aby usunąć również nie rozwijane rozszerzenie mssql oraz rozszerzenie mysql oparte na natywnych bibliotekach dostarczanych przez producenta bazy, a zamiast niego silniej promować mysqli i pdo. Argumentacja była taka, że rozszerzenie mssql również nie jest rozwijane i są lepsze sposoby na komunikacje z tą bazą np. w windowsie oficjalny microsoftowy driver a na linkusie odbc. Natomiast co do drivera mysql, że nie jest to natywny PHP-owy driver. Padł również argument, że powinno się ograniczać ilość dostępnych sposobów realizacji jednej rzeczy.

A Wy co sądzicie ?

Czy należy usunąć rozszerzenie SQLite2 z dystrybucji ? Czy należy pozbyć się drivera MySQL dostarczanego przez producenta na rzecz mysqli i pdo, a może zostawić obie rzeczy by była lepsza kompatybilność wsteczna ?

Autor wpisu: sokzzuka, dodany: 17.06.2010 22:51, tagi: php

W poprzednich częściach tutorialu omawiałem jak stworzyć szkielet aplikacji webowej w Pythonie przy użyciu mod_wsgi oraz jak wykonywać proste operacje na bazie (select, insert). Dzisiejszy wpis będzie o odczytywaniu informacji z plików w popularnych formatach XML i CSV.

Jak zaraz zobaczycie w obu językach wygląda to podobnie, najpierw parsowanie CSV w Pythonie oraz wyświetlanie HTML-owej tabelki:

import csv
 
def test(path):
    sFile = path + 'files/sample.csv'
    oReader = csv.reader(open(sFile), delimiter=',', quotechar='"')
    aResult = []
    for row in oReader:
        aResult.append(row)
 
    sResult = '<table><tbody>'
    for row in aResult:
        sResult += '<tr>'
        for cell in row:
            sResult += '<td>' + cell + '</td>'
        sResult += '</tr>'
 
    sResult += '</tbody></table>'
    return sResult

Ekwiwalent w php

<?php
$sPath = 'res' . DIRECTORY_SEPARATOR . 'csv' . DIRECTORY_SEPARATOR . 'sample.csv';
 
$rFile = fopen( $sPath, 'r' );
$aResult = array();
$mResult = array();
do {
    $mResult = fgetcsv( $rFile );
    $aResult[] = $mResult;
} while ($mResult !== false);
 
$iRows = count($aResult);
unset ($aResult[$iRows-1]);
?>
<table>
    <tbody>
<?php foreach ($aResult as $row): ?>
            <tr>
        <?php foreach ($row as $cell): ?>
                    <td><?php echo $cell ?></td>
            <?php endforeach; ?>
                    </tr>
            <?php endforeach; ?>
    </tbody>
</table>

Jak widać kod w Pythonie jest troszkę krótszy ze względu na większą abstrakcje – w PHP można by osiągnąć ten sam efekt poprzez opakowanie funkcji fgetcsv w obiekt implementujący interfejs Iterator.

Naszym kolejnym obiektem zainteresowanie będzie parsowanie plików XML, za zadanie weźmiemy sobie wyciągnięcie z pliku RSS wszystkich tytułów wpisów, będziemy korzystać z pasera typu DOM.

Kod pythonowy:

def test(path):
    from xml.dom.minidom import *
 
    sFile = path + 'files/rss.xml'
    # @type oDom xml.dom.minidom.Document
    oDom = parse(sFile)
 
    lTitles = oDom.getElementsByTagName('title')
    output = ''
 
    output += "<h1>Titles</h1>"
    output += "<ul>"
 
    for node in lTitles:
        output += "<li>" 
        output += node.childNodes[0].nodeValue
        output += "</li>"
    output += "</ul"
    return output

Kod w PHP:

$sPath = 'res'.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'rss.xml';
 
$oDom = new DOMDocument();
$oDom->preserverWhiteSpace = false;
$oDom->load($sPath);
 
$oTitles = $oDom->getElementsByTagName('title');
echo "<h1>Titles</h1>";
echo "<ul>";
foreach($oTitles as $title){
    $sTitle = $title->nodeValue;
    echo "<li>",$sTitle,"</li>";
}
echo "</ul>";

Widać kilka zasadniczych różnic w obu językach, po pierwsze aby parsować dokument XML w php należy użyć metody DOMDocument::load, natomiast w Pythonie mamy metode parse modułu minidom.

Po drugie w PHP jeżeli mamy noda którego jedyną zawartością jest tekst, to możemy się do niego dostać przez właściwość nodeValue, natomiast Pythonowy parser widzi nod z tekstem wewnątrz jak nod z dzieckiem, które to jest nodem tekstowym.

Tym wpisem prawdopodobnie zakończę serię “Aplikacje webowe w Pythonie dla programistów PHP”, mam nadzieje, że udało mi się zachęcić Was do zabawy z tym ciekawym językiem i spojrzenia z innej perspektywy na znane Wam zapewne zagadnienia w programowaniu.

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

Autor wpisu: sokzzuka, dodany: 15.06.2010 00:02, tagi: zend_framework, php

Kaskadowość większości ludzi związanymi z web developementem pewnie kojarzy się z kaskadowymi arkuszami styli (CSS). Jest to poniekąd słuszne skojarzenie, ponieważ daje pewne wyobrażenie czym ona jest.

W CSS-ach kaskadowość znaczy nie mniej, nie więcej tyle, że właściwości stylu zdefiniowane dla elementów wyżej w drzewie dokumentu propagują się w dół drzewa aż do momentu kiedy nie zostaną nadpisane przez właściwości elementów niżej w hierarchii.

W PHP istnieje technika oparta na podobnych założeniach, realizowana dzięki magicznej funkcji __autoload. Na czym więc polega ? Załóżmy, że mamy pewną hierarchię klas: --A

---B ----E

---C ----D ----E Każda z tych klas dziedziczy bezpośrednio lub pośrednio z klasy A. Załóżmy teraz, że chcielibyśmy zmienić zachowanie wszystkich klas dziedziczących z A. Jednym z rozwiązań jest po prostu modyfikacja odpowiedniej metody z klasy A, jest to oczywiście najlepsze wyjście, z kilkoma wyjątkami, z których najpoważniejszym jest to, że klasa A należy do pewnej zewnętrznej biblioteki.

Klasycznym przykładem tego typu są formularze dziedziczące z Zend_Form. Mamy już gotowych n-bardzo dużo formularzy, jednak nagle okazało się, że trzeba im globalnie coś zmienić. Nie możemy za bardzo modyfikować samego Zend_Form-a ponieważ należy on do zewnętrznej biblioteki i w razie modyfikacji go, będzie problem z migracją do nowszych wersji frameworka.

Zmiana tych n-bardzo wielu klas, aby dziedziczyły z innej pośredniej klasy, która dziedziczy z Zend_Form będzie procesem bardzo pracochłonnym.

W tym momencie z pomocą przychodzi nam kaskadowość. Dzięki niej będziemy mogli podmienić oryginalną klasę Zend_Form, bez modyfikacji jej kodu.

Po pierwsze będzie nam potrzebna odpowiednia struktura katalogów: -test_cascading --base ---application ----forms ---library ----Zend --modified ---library ----Zend

Naszą zmodyfikowaną klasę Zend_Form umieścimy w podkatalogu “modified” w takiej samej ścieżce jak w katalogu “base”.

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

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.