Tomasz Tomczyk - Programista PHP, Kraków - Strona główna > php, programowanie > PHP 5.4 – nowości, nowości część pierwsza

PHP 5.4 – nowości, nowości część pierwsza

Wrzesień 3rd, 2012

Wraz z wydaniem PHP w wersji 5.4 otrzymujemy parę nowych konstrukcji i funkcjonalności. Może wersja 5.4 nie wprowadza tylu zmiana co wersja 5.3 jednak warto się zapoznać z tym co oferuje. Wpisie tym pominę temat „Cech” (Trait), którym będzie poświęcony osobny wpis i skupię się na pozostałych nowościach. Starałem wybrać się te najistotniejsze i w miarę możliwości wysycić temat. Jeśli uważacie, że pominąłem coś znaczącego to piszcie w komentarzach.

Na początku napiszę, że nie siliłem się na wymyślanie jakiś twórczych przykładów i większość z nich pochodzi z strony php.net.

Tablice

Uproszczona składnia deklaracji tablic.
    $a = array(1, 2, 3, 4);
    $a = [1, 2, 3, 4]; 

    $b = array('one' => 1, 'two' => 2, 'three' => 3, 'four' => 4);
    $b = ['one' => 1, 'two' => 2, 'three' => 3, 'four' => 4];

Według mnie to jest przyjemne uproszczenie składni, na pewno będę używał :)

Array dereferencing

Nie tłumaczę, ponieważ nie znam dobrego polskiego tłumaczenia.
Dzięki array dereferencing do zwracanej tablicy przez funkcję lub metodę możemy się odwołać bezpośrednio, bez użycia tymczasowych zmiennych.

    // przykładowa funkcja
    function getArray() {
        return array(1, 2, 3);
    }

    // poprzednie wersje
    $tmp = getArray();
    echo $tmp[1];		// wyświetli: 2

    // PHP 5.4+
    echo getArray()[1];	// wyświetli: 2

    // trochę bardziej złożona tablica zwracana przez funkcję
    function getBigArray() {
        return array("test" => array("foo" => "bar"));
    }
    echo getBigArray()['test']['foo']; // wyświetli: "bar"

    // kolejny przykład
    $a = "hello world";
    echo explode(" ", $a)[0]; // wyświetli "hello"

    // inne zastosowania
    list(, $secondElement) = getArray();
    $object->method()[0]->otherMethod();

Funkcjonalnoś (a raczej nowa składnia) wygląda bardzo interesująco. W końcu pozbędziemy się wielu tymczasowych zmienny typu „$tmp”. Jednak z drugiej strony na początku może odrobię pomniejszyć czytelność kodu, poniewaz nie do końca będzie wiadomo jaką faktycznie ma postać zwracana tablica przez funkcję/metodę. Jednak nie jest to według mnie jakaś istotna przeszkoda aby tego nie stosować. Potrzeba tylko chwili obycia i wyrobienia sobie odpowiednich nawyków.

Klasy

Aby nie było tak, że tylko tablice zostały upgrejdowane to klasy również dostały nowe możliwości ;)
Podobnie jak z tablicami nie potrzeba już tworzyc tymczasowych zmiennych będących uchwytami na referencje do obiektu.

    // PHP 5.3 i wcześniej
    $boo = new Boo();
    $boo->getBar();

    // PHP 5.4
    (new Boo)->getBar();

Nowa składnia: Class::{expr}()

    // nazwa metody
    $clasMethod = 'myMethod';

    // możliwe wywołania metody
    $test = new Test();
    $test->myMethod();
    $test->$clasMethod();
    $test->{'myMethod'}();

    // możliwe wywołania statycznej metody
    Test::myMethod();
    Test::$clasMethod();
    Test::{'myMethod'}();

short tags

Konstrukcja:
<?=”Coś do wyświetlenia” ?>;

Będzie działać zawsze, bez względu jaką flagę ustawiliśmy dla short_open_tag w php.ini. W końcu będzie można się pozbyć konstrukcji <?php echo „Coś do wyświetlenia” ?> z szablonów, niby parę literek mniej a cieszy :)

Interfejs: JsonSerializable

Dzięki zaimplementowaniu tego interfejsu możemy wymusić reprezentację obiektu w postaci JSON po wywołaniu funkcji json_encode()

class myClass implements JsonSerializable {
    private $data, $multiplier;
    public function __construct($a, $b) {
        $this->data = $a;
        $this->multiplier = $b;
    } 

    public function jsonSerialize() {
        return array_fill(0, $this->multiplier, $this->data);
    }
}

    echo json_encode(new myClass(123, 3));    // [123,123,123]

Native Session Handler Interface

Obiektowa notacja do definiowania handler’ow sesyjnych.

Wprowadzony został nowy interfejs SessionHandlerInterface, który wymusza implementację metod do obsługi sesji.
Jak również dodana została nowa klasa SessionHandler, która implementuje powyższy interfejs

interface SessionHandlerInterface {
	/* Metody */
	abstract public bool close ( void )
	abstract public bool destroy ( string $session_id )
	abstract public bool gc ( string $maxlifetime )
	abstract public bool open ( string $save_path , string $session_id )
	abstract public string read ( string $session_id )
	abstract public bool write ( string $session_id , string $session_data )
}

SessionHandler implements SessionHandlerInterface {
	/* Metody */
	public bool close ( void )
	public bool destroy ( string $session_id )
	public bool gc ( int $maxlifetime )
	public bool open ( string $save_path , string $session_id )
	public string read ( string $session_id )
	public bool write ( string $session_id , string $session_data )
}

Jeśli z jakiegoś powodu zachodzi potrzeba przedefiniowania handlerów, możemy zrobić to trochę zgrabniej nie w poprzednich wersjach.

// zamiast
session_set_save_handler(
	array($this,"open"),
	array($this,"close"),
	array($this,"read"),
	array($this,"write"),
	array($this,"destroy"),
	array($this,"gc")
); 

// robimy coś takiego
MySessionHandler implements SessionHandlerInterface {
	/* metody */
	...
}

// lub w zależności od potrzeb
MySessionHandler extends SessionHandler {
	/* metody */
	...
} 

session_set_save_handler(new MySessionHandler);

Może nie jest to nie wiadomo jakie usprawnienie, jednak jest to kolejny krok w stronę obiektowości języka.

Callable

Nowy typ danych który możemy użyć w definicji funkcji dla parametrów.

Za pomocą tego typu możemy wymusić aby przekazywany parametr był funkcją lub metodą. Dzięki temu możem wewnątrz funkcji lub metody bezpiecznie odwoływać się do parametru jak do funkcji.

    function testCall(callable $x) {
        return $x();
    } 

    // możemy jej użyć w następujący sposób:
    testCall(function () { });
    testCall("function_name");
    testCall(['class', 'staticMethodName']);
    testCall([$object, 'methodName']);
    testCall($invokableObject);

Jeszcze chwilę i doczekamy się kontroli typów prostych w php :D

$this w funkcjach anonimowych i domknięciach

Od wersji php 5.4 zmienna $this jest widoczna w domknięciach oraz funkcjach anonimowych i odnosi się do uchwytu klasy w której została (funkcja) zdefiniowana.

class foo {
	function printText() {
		echo "jestesmy wewnątrz metody printText klasy foo";
	} 

	function getAnonFunc() {
		return function() { $this->printText(); };
	}
} 

class bar {
	public function __construct(foo $o) {
		$anonFunc = $o->getAnonFunc();
		$anonFunc();
	}
}

new bar(new foo()); // wyświetli “jestesmy wewnątrz metody printText klasy foo”

W php 5.3 bardzo brakowało powyższej możliwości, trzeba było kombinować z przekazywaniem z „use”. Dzięki temu uproszczone zostało używanie funkcji anonimowych/domknięć w php.

Pasek postępu uploudu pliku

Wspomaganie implementacji mechanizmu paska postępu uploudu.
Konstrukcja formularza:

" value="johannesupload" />

Dzięki temu serwer będzie odpytywany parokrotnie o postęp wgrywania pliku/ów. Zwracana będzie informacja zawarta w $_SESSION["upload_progress_johannesupload"].

Wbudowany serwer (developerski)

Podstawowy sposób uruchomienia serwera:

$ cd ~/public_html
$ php -S localhost:8000

PHP 5.4.4-4~oneiric+1 Development Server started at Thu Aug 16 15:49:21 2012
Listening on localhost:8081
Document root is /home/me/public_html
Press Ctrl-C to quit.

Uruchomienie z określeniem katalogu „document root”:

$ cd ~/public_html
$ php -S localhost:8000 -t foo/

PHP 5.4.0 Development Server started at Thu Jul 21 10:50:26 2011
Listening on localhost:8000
Document root is /home/me/public_html/foo
Press Ctrl-C to quit

Uruchomienie z określeniem katalogu „document root” oraz pliku rutera, w którym będą reguły routingu dla naszej aplikacji.

php -S localhost:8081 -t /var/www router.php

PHP 5.4.4-4~oneiric+1 Development Server started at Thu Aug 16 15:49:21 2012
Listening on localhost:8081
Document root is /var/www
Press Ctrl-C to quit.

Plik router.php tworzymy ręcznie, odpowiedni dla aplikacji którą testujemy, przykładowo:

if (preg_match('!\.php$!', $_SERVER["REQUEST_URI"])) {
	require basename($_SERVER["REQUEST_URI"]);
} else if (strpos($_SERVER["REQUEST_URI"], '.')) {
	return false; // serve the requested file as-is.
} else {
	Framework::Router($_SERVER["REQUEST_URI"]);
}

Uwagi

  • jest to nowa funkcjonalność w php, więc należy używać z rozwagą i zwracać uwgę na ewentualne błędy/problemy
  • domyślnym plikiem wejścia jest plik: index.php
  • WAŻNE – wbudowany serwer został stworzony jako wsparcie podczasz developowania aplikacji a NIE jako serwer docelowy
  • brak wsparcia dla SSL’a

Usprawnienia dotyczące szybkości i stabilności

Osobiście nie robiłem jeszcze żadnych testów wydajności, tak więc zamieszczam tylko to co powiedzieli wydawcyc php 5.4

  • 5.4 w tej chwili jest najszybszą wersją PHP
  • średni zwrost dla aplikacji wacha się pomiędzy 5-20%
  • dla statycznych stron wzrost jest zrzędu 15-20%
  • zmniejszono zużycie pamięci o około 25%

Kompatabilność

PHP 5.4 nie jest w pełni kompatabilne (jak nie w pełni czyli wcale ;) ) z wcześniejszymi wersjami języka.

Usunięte zostało:

  • SQLite 2 (zastąpione przez SQLite 3)
  • Safe Mode
  • Magic Quotes – aplikacje które tego używały powinny zostać zmodyfikowane
  • Dyrektywy register_globals i register_long_arrays
  • Call-time pass by reference foo(&$bar) – http://docs.php.net/manual/en/language.references.pass.php
  • konstrukcje break i continue nie wspierają już wzrażeń np:
        break 1 + foo() * $bar;
        break $foo;
        continue $bar;
    

    Statyczne argumenty nadal działają.

            break 2;
        

    Trzeba zaznaczyć że mimo powyższego przykładu konstrukcje

        break 0;
        continoue 0;
    

    nie działają.

Zmiany w obsłudze stringów

  • Modyfikacja dotycząca posługiwania się stringami porzez notację tablicową.
    Dla wyrażenia:

        // php 5.4
        isset($a['test']);  //(zakładamy że zmienna $a jest dowolnym stringiem)
        // zostanie zwrócone: false, 
    
        empty($a['test']);
        //zwróci true.

    Jednocześnie oba wyrażenia wygenerują E_WARNING podczas ich użycia.
    Warto zauważyć że wyrażenia takie jak 11.4 i 44 test są traktowane jako nie numeryczne co powoduje zgłoszenie E_WARNING, jednak zachodzi również konwersja na int 11 i 44. Konwersja jest wymuszona poprzez podtrzymanie wstecznej kompatabilności z wcześniejszymi wersjami php.

  • Użycia jako offsetu typów double, bool, null wygeneruje E_NOTICE.
  • Numeryczne offsety np $a[2] nadal będzie działać poprawnie.
  • Konwersja tablicy na string będzie generowaci E_NOTICE, rezultatem tej operacji nadal będzie string „Array”

Pozostałem zmiany i modyfikacje

  • Strefa czasowa może być ustawiona tylko w php.ini w opcji date.timezone lub przy pomocy funcji date_default_timezone_set(). PHP nie będzię się starało zgadnąć jaka strefa jest używana (oczywiście jeśli wcześniej jej nie ustawiliśmy). Taka sytuacja spowoduje zgłoszenie E_WARNING.
  • Konstrukcja:
    function foo($_GET, $_POST) {}

    Spowoduje zgłoszeniem błędu E_ERROR

  • Ustawienei E_ALL oznacza teraz również ustawienie E_STRICT.
  • Tablice powstałe w wyniku rzutowania/konwersji obiektu SimpleXMLElement w końcu zawierają wszystkie węzły (nie tylko te z pierwszego dopasowania. Będą one teraz zawsze wyświetlana przy użyciu funkcji var_dump() oraz print_r().
  • Domyślne kodowanie zostało zmienione z ISO-8859-1 na UTF-8
    Ma to wpływ na:

    • dane wejściowe (GET, POST, default_charset INI)
    • magazyny danych np kodowanie bazy danych (połączenia)
    • funkcji, np: htmlspecialchars, htmlentities

Usunięte funkcje (aliasy do funkcji) – te warte wzmianki według mnie :)

  • funkcje – session_is_registered(), session_register() and session_unregister().
  • aliasy – mysqli_bind_param(), mysqli_bind_result(), mysqli_client_encoding(), mysqli_fetch(), mysqli_param_count(), mysqli_get_metadata(), mysqli_send_long_data(), mysqli::client_encoding(), mysqli_stmt::stmt().

Funckje oznaczone jako „deprecated” w php 5.4

  • mcrypt_generic_end()
  • mysql_list_dbs()

Zmodyfikowane funkcje:

  • debug_backtrace() i debug_print_backtrace() – dodano dodatkowy parametr określający limit poziomów wywywołań, które zostaną zwrócone.
  • is_link() – w php 5.4 zmodyfikowano tak aby działała poprawnie z linkami symbolicznymi pod Windows Vista+.

Nowe funkcje – również wybrane

  • PHP CORE
    • hex2bin() – wcześniej mieliśmy tylko bin2hex() teraz mamy obie
    • http_response_code() – pobiera lub ustawia (jeśli podamy parametr) kod odpowiedzi http
    • get_declared_traits() – zwraca listę zadeklarowanych „cech”
    • trait_exists() – sprawdzamy czy „cecha” istnieje
    • header_register_callback(callback func) – rejestruję funkcję która będzie wykonana wtedy gdy PHP zacznie wysyłać odpowiedź do przeglądarki, a dokładniej w chwili gdy zostaną przygotowane nagłówki do wysłania ale jeszcze nie wysłane. Dzięki temu możemy manipulować nagłówkami które wysyłamy.
  • SPL:
    • class_uses() – zwraca cechy (traits) używane przez daną klasę
  • Session:
    • session_status() – zwraca bierzący status sesji
    • session_register_shutdown() – zamyka sesję
  • Mysqli:
    • mysqli_error_list() – zwraca listę błędów które wystąpiły podczas wykonywania ostatniego zapytania
    • mysqli_stmt_error_list() – zwraca listę błędów które wystąpiły podczas wykonania ostatniego statmentu (statement executed)

Podsumowanie

Razem z wersją PHP 5.4 dostaliśmy sporą paczkę nowych możliwości. Z pewnością to nie jest jakaś rewolucja. Można to bardziej nazwać ewolucją języka która zapoczątkowana była rewolucją która nastąpiła podczas przejścia z wersji 4.x na 5.0. Według mnie wprowadzone zmiany to krok naprzód.

W następnym artykule opiszę chyba największą zmianę jaką niesie PHP 5.4, czyli „cechy” (traits). Jest to bardzo ciekawy mechanizm, który z jednej strony daje nam możliwość obejścia problemu braku wielodziedziczenia w php, jednak z drugiej strony daje również możliwość stworzenia super nieczytelnego kodu :/. Dlatego użycie cech musi być dogłębnie przemyślane, ale o tym już w następnym wpisie.

  1. Przemek
    Wrzesień 4th, 2012 at 22:45 | #1

    Kolejny profesjonalny artykuł o Php, już nie mogę się doczekać co napiszesz o cechach :-)

  2. Alex
    Wrzesień 6th, 2012 at 14:28 | #2

    Ano Pan Tomasz znowu zadziwia.
    Też bym tak popisał, ale nie mam czasu ;(
    Byle tak dalej! :)

  3. Październik 19th, 2012 at 04:06 | #3

    Posts like this make the internet such a terausre trove

  1. Brak jeszcze trackbacków
Komentarze są zamknięte