Miesięczne archiwum: Październik 2013

Zalecane standardy i dobre praktyki

Uważam, że PHP jest językiem bardzo „elastycznym”. Można napisać skrypt księgi gości (kto od takich rzeczy nie zaczynał? ;)) po przerobieniu tutoriala z internetu, można też napisać skomplikowaną i rozbudowaną aplikację internetową. W wszystko w jednym, tym samym języku.

Z jednej strony jest to zaleta – pozwala stosunkowo szybko osiągnąć działający efekt oraz pozwala się uczyć w obrębie jednego języka i rozwijać swoje umiejętności. Z drugiej strony jest to wada, bo pozwala pisać kod niechlujny, może nawet do tego zachęca/przyzwyczaja – skoro pierwsze efekty można było osiągnąć „metodą Copy’ego Paste’a”, to dlaczego kolejne mają wymagać więcej pracy?. W efekcie można spotkać dziwaczny kod, pełen funkcji zadeklarowanych tam gdzie akurat były potrzebne, zmiennych globalnych nagminnie używanych w metodach/funkcjach, kodu HTML, CSS, JS, PHP przemieszanego w obrębie jednego pliku etc. Obiektowość również się zdarza, ale budowa obiektów i ich wykorzystanie nie napawają optymizmem.

Myślę jednak, że nie należy winić języka. Jeżeli ktoś ma „głód wiedzy”, to taki kod będzie tworzył na początku, a później będzie się uczył, uczył i uczył jak programować coraz lepiej. Za cenną pomoc w tej nauce uważam dwie inicjatywy: PHP Framework Interop Group i PHP: The Right Way.

PHP Framework Interop Group

Jest to grupa ustalająca propozycje standardów dla kodu pisanego w języku PHP. Wypowiedzieć się w dyskusji może każdy chętny, jednak głosować mogą tylko przedstawiciele projektów (np. Zend Framework, Symfony2, Drupal, Doctrine, eZ Publish). Do tej pory grupa uzgodniła i zatwierdziła 4 standardy:

  • PSR-0, Autoloading Standard – opisuje wymogi, jakie musi spełniać autoloader, żeby mógł obsługiwać różne biblioteki;
  • PSR-1, Basic Coding Standard – opisuje ogólne wymogi kodu (kodowanie plików, tagi PHP, klasy, metody, właściwości, stałe);
  • PSR-2, Coding Style Guide – opisuje szczegółowe zalecenia formatowania kodu;
  • PSR-3, Logger Interface – opisuje interfejs dla loggerów, którego użycie umożliwi obsługę logów w różnych aplikacjach i bibliotekach z wykorzystaniem tego samego mechanizmu obsługi logów.

Nikt nie wymaga stosowania PSR-*, jednak uważam to za dobrą praktykę. Dodatkowo pisanie kodu przestrzegającego tych standardów może ułatwić jego późniejsze wykorzystanie jako bibliotek czy wykorzystanie w swoim projekcie zewnętrznych bibliotek.

Strona FIG znajduje się tutaj, jednak zawiera tylko zatwierdzone standardy. Natomiast propozycje kolejnych można znaleść na GitHubie grupy – tutaj.

PHP: The Right Way

Ten projekt jest zbiorem dobrych rad, kierunków rozwoju, narzędzi/technik którymi warto się zainteresować chcąc profesjonalnie programować w PHP. Dodatkowo zakres tematyczny jest bardzo szeroki – od pierwszych kroków, przez zarządzanie zależnościami (Composer, PEAR), po serwery, testowanie i cache. Dodatkowo strona jest przetłumaczona na język polski i dostępna tutaj.

NetBeans 7.4 wydany

Jeden z wczesniejszych wpisów poświęciłem wydaniu NetBeans 7.4 w wersji beta. Wczoraj, 15 października, została wydana wersja stabilna tego IDE.

W poprzednim wpisie wymieniłem ciekawsze zmiany dotyczące programowania aplikacji internetowych w PHP, natomiast pełną listę zmian można przejrzeć na stronie projektu. Jest tam również link do pobrania instalatora.

Zmiany w certyfikacji Zend

Pierwsze wydania głównych (obecnie) gałęzi PHP miały miejsce:

  • 5.3.0 – 30 czerwca 2009r
  • 5.4.0 – 1 marca 2012r
  • 5.5.0 – 20 czerwca 2013r

Natomiast egzamin na certyfikat z PHP przez dłuższy czas dotyczył wersji 5.3, jednak nadchodzą zmiany.

Po pierwsze dotychczasowy egzamin (obejmujący PHP 5.3) będzie dostępny tylko do 31 grudnia 2013 roku. W jego miejsce pojawił się egzamin obejmujący PHP 5.5. Zmienia się również nazwa, teraz będzie to „Zend Certified PHP Developer”, co Zend tłumaczy dopasowaniem nazwy do innych certyfikatów IT. Według informacji ze strony rejestracja na nową wersję egzaminu była dostępna od 3 października, natomiast sam egzamin od dziś (7 października).

Nadal dostępny jest Study Guide dla wersji 5.3 a prace nad jego aktualizacją do 5.5 trwają i efekty mają być w przyszłym miesiącu (podejrzewam, że chodzi o listopad).

Źródło: PHP Certification

Typ wyliczeniowy – SplEnum i alternatywy

We wpisie Magiczne „cyferki” pisałem o używaniu stałych zamiast magicznych cyfr, które dla osoby nie znającej szczegółów projektu nic nie znaczą. Stałe zamiast cyfr są postępem, jednak pozostaje problem poprawności danych. Na przykład wartość 1 może mieć status obiektu firmy, osoby i wielu innych obiektów w aplikacji. W dodatku dla każdego obiektu może on oznaczać coś zupełnie innego. Z drugiej strony przy większej liczbie statusów w jednym obiekcie i mniejszej w innych można przez pomyłkę przypisać status innego obiektu, który jest poza zakresem danego obiektu.

Krótko mówiąc pozostaje problem ograniczenia możliwości ustawienia statusu tylko z określonego zakresu/typu. Typ jest tutaj istotną wskazówką – m.in. w Javie są tytułowe typy wyliczeniowe, które pozawalają zdefiniować nowy typ, dla określonego zbioru wartości, a język poprzez typowanie parametrów metody przypilnuje, żeby ustawiać statusy tylko dozwolonego typu.

W PHP również jest typowanie parametrów (tylko dla typów złożonych) i jak się okazuje w bibliotece SPL znajduje się nawet klasa dla typów wyliczeniowych – SplEnum. Jej budowa jest dość prosta a przykłady z manuala klarowne. Jest jednak jeden problem – nie jest standardowym elementem języka i wymaga doinstalowania rozszerzenia PECL na serwerze. Dla posiadaczy serwerów dedykowanych/VPS nie stanowi to problemu, jednak przy uruchamianiu aplikacji na hostingu współdzielonym zainstalowanie tego rozszerzenia zależy od administratora.

Jak wspominałem trochę wyżej budowa klasy jest dość prosta, więc zamiast zastanawiać się nad dostępnością/możliwością instalacji rozszerzenia na serwerze można napisać odpowiednik tej klasy samemu, poniżej przykładowa implementacja.

<?php

/**
 * My implementation of alternative SplEnum 
 * @link http://php.net/manual/en/class.splenum.php
 */
class MyEnum 
{
    /**
     * Value of object
     * @var mixed
     */
    private $value;
    
    /**
     * Name of const with default value
     * @var string
     */
    private $defaultName = '__default';
    
    /**
     * Reflection object
     * @var ReflectionClass
     */
    private $reflection;

    /**
     * Create object
     * @param mixed $initialValue
     * @throws UnexpectedValueException
     */
    public function __construct($initialValue = null)
    {
        if ($initialValue && in_array($initialValue, $this->getConstList())) {
            $this->value = $initialValue;
        } elseif (!$initialValue && $this->getDefault()) {
            $this->value = $this->getDefault();
        } else {
            throw new UnexpectedValueException('Value not a const in enum '. get_class($this));
        }
    }
    
    /**
     * Get array of class consts
     * @param boolean $includeDefault
     * @return array
     */
    public function getConstList($includeDefault = false)
    {
        $tmp = $this->getReflection()->getConstants();
        if (!$includeDefault && array_key_exists($this->defaultName, $tmp)) {
            unset($tmp[$this->defaultName]);
        }
        return $tmp;
    }
    
    /**
     * Get value of object
     * @return mixed
     */
    public function getValue()
    {
        return $this->value;
    }
    
    public function __toString()
    {
        return (string) $this->getValue();
    }
    
    /**
     * Get default value from class
     * @return mixed
     */
    protected function getDefault()
    {
        return $this->getReflection()->getConstant($this->defaultName);
    }

    /**
     * Get instance of class reflection
     * @return ReflectionClass
     */
    protected function getReflection()
    {
        if (!$this->reflection) {
            $this->reflection = new ReflectionClass($this);
        }
        
        return $this->reflection;
    }
}

Myślę, że kod jest czytelny i jasny. Dla przypomnienia odczytanie stałych zadeklarowanych w klasie jest realizowane z wykorzystaniem mechanizmu refleksji, który pozwala na analizowanie struktury/budowy obiektu w trakcie wykonania kodu.

Teraz bardzo prosty kod z przykładem użycia:

<?php
function processOption(Opcje $opcja)
{
    echo($opcja);
}

class Opcje extends MyEnum
{
    const __default = 2;
    
    const OPCJA1 = 1;
    const OPCJA2 = 2;
}

$obj = new Opcje();
processOption($obj);

Powyżej znajduje się definicja funkcji, która przyjmuje parametr typu Opcje i definicja tej klasy. Klasa ogranicza się jedynie do dziedziczenia po MyEnum i deklaracji stałych, cała funkcjonalność jest dziedziczona. Przykładowy kod wyświetli tylko 2, ponieważ taka jest wartość domyślna typu wyliczeniowego i typ zgadza się z oczekiwanym typem parametru funkcji.

W przypadku próby utworzenia obiektu z wartością spoza zdefiniowanych stałych zostanie rzucony wyjątek UnexpectedValueException, natomiast przy próbie przekazania do funkcji parametru innego typu:

<?php
processOption(2);
// wynik: Catchable fatal error: Argument 1 passed to processOption() 
// must be an instance of Opcje, integer given, called in...

Wygląda na to, że problem jest rozwiązany – nie można pomyłkowo przypisać innej wartości i tego nie zauważyć.

Dodatkowo, na polskiej planecie PHP pojawił się jakiś czas temu wpis z pomysłem implementacji typów wyliczeniowych w oparciu o koncepcję z Javy – odsyłam do tego wpisu (autorem jest Sebastian Malaca). Warto również przyjrzeć się komentarzom pod tym wpisem, ponieważ można tam znaleść kolejną/bardziej rozbudowaną alternatywę dla SplEnum.