PHP 5.5

De nouvelles évolutions
pour notre langage !

Pascal MARTIN, http://blog.pascal-martin.fr / pmartin@php.net / @pascal_martin

Appuyez sur s pour ouvrir les notes présentateur dans une nouvelle fenêtre.

PHP 5.2

Plus supporté depuis janvier 2011 !

PHP 5.3

PHP 5.3.0 : 30 juin 2009

Juillet 2013 : "EOL" atteinte !
Correctifs de sécurité, uniquement, pendant un an (→ juillet 2014)

PHP 5.4

PHP 5.4.0 : 1er mars 2012

PHP 5.4.17 : 4 juillet 2012
Old Stable

  • Traits
  • Serveur web de test intégré
  • Syntaxe courte pour les tableaux : $var = [1, 2, 3]
  • ma_fonction()[0]
  • Format de nombres binaires : 0b10110111
  • Suppression de register_globals, magic_quotes, safe_mode
  • Nouveaux itérateurs pour la SPL, classes pour intl, JsonSerializable, ...

PHP 5.5

PHP 5.5.0 : 20 juin 2013

PHP 5.5.1 : 18 juillet 2013
Stable

ext/opcache

Cache d'opcodes intégré

http://php.net/opcache

  • Anciennement Zend Optimizer+, open-sourcé
  • Extension fournie avec PHP ; pas "intégrée"
  • Cache d'opcodes toujours "à jour" et fonctionnel
  • Futur : intégration au moteur, optimisations ?
  • Pas APC ?
  • Cache de données : APCu, YAC

Lire un fichier ?


<?php
$file = fopen(__DIR__ . '/exemple.txt', 'r');
while (!feof($file)) {
    echo trim(fgets($file)), "\n";
}
fclose($file);
                    

Mélange du code de parcours et d'affichage

Séparer parcours de l'affichage


<?php
$array = file(__DIR__ . '/exemple.txt');
$array = array_map('trim', $array);

foreach ($array as $val) {
    echo $val, "\n";
}
                    

Fichier entier chargé en mémoire

Avec un Iterator ?


<?php
class LinesIterator implements Iterator {
    protected $file;
    protected $current, $indiceCurrent;
    public function __construct($path) {
        $this->file = fopen($path, 'r');
    }
    public function rewind() {
        fseek($this->file, 0, SEEK_SET);
    }
    public function valid() {
        if (feof($this->file)) {
            fclose($this->file);
            return false;
        }
        return true;
    }
    public function current() {
        $this->current = trim(fgets($this->file));
        return $this->current;
    }
    public function key() {
        return $this->indiceCurrent;
    }
    public function next() {
        $this->indiceCurrent += 1;
    }
}
                    

$iterator = new LinesIterator(__DIR__ . '/exemple.txt');
foreach ($iterator as $val) {
    echo $val, "\n";
}
                    

Heu ???

Et avec un Generator !


<?php
$generator = function ($path) {
    $file = fopen($path, 'r');
    while (!feof($file)) {
        yield trim(fgets($file));
    }
    fclose($file);
};

$iterator = $generator(__DIR__ . '/exemple.txt');
foreach ($iterator as $val) {
    echo $val, "\n";
}
                    

\o/

Generators

Qu'est-ce qu'un Generator ?

  • Une fonction, qui yielde une ou plusieurs clefs/valeurs
  • Un Generator est un Iterator, et implémente Traversable
  • next() avance de yield en yield ; current() et key() retournent la dernière valeur et la dernière clef yieldées
  • rewind() ne peut être appelée que si aucune valeur n'a été yieldée

Nouveau mot-clef yield

  • yield : lève une clef auto-incrémentée, et valeur null
  • yield $value : lève une clef auto-incrémentée et une valeur donnée
  • yield $key => $value : lève une clef et une valeur données

Generators

Renvoi de valeur au Generator : send()


<?php
$myGenerator = function () {
    $sent = (yield "Hello");
    var_dump($sent);

    $sent = (yield 42 => "World");
    var_dump($sent);
};

$generator = $myGenerator();

var_dump( $generator->current() );
$generator->send("retour 1er yield");

var_dump( $generator->current() );
$generator->send("retour 2nd yield");
                    

string(5) "Hello"
string(16) "retour 1er yield"
string(5) "World"
string(16) "retour 2nd yield"
                    

Bloc finally


<?php
try {
    // ...
}
catch (Exception $e) {
    // Si exception levée dans le bloc try
}
finally {
    // Dans tous les cas, après le bloc try ou le bloc catch
}
                    

Bloc finally

Nouveau mot-clef finally

  • Bloc finally toujours exécuté, après try ou catch
  • Même si try ou catch contiennent un return !
  • Pas si die() ou Fatal Error

Utilité typique : opérations de nettoyage

API de hachage de mots de passe

  • Comment saler/crypter des mots de passe ?
  • Besoin récurrent

Hacher un mot de passe


<?php
$password = '@zErt|123';
$hash = password_hash($password, PASSWORD_DEFAULT);
var_dump($hash);
                        

string(60) "$2y$10$1xpgT3cLt86T1guNcG0UW.pd6WFKmqqjp08ZgxR.ztpJ0TmdQMh9C"
                        

API de hachage de mots de passe

Vérifier la validité d'un mot de passe


<?php
$password = '@zErt|123';
$hash = '$2y$10$0XPjx7G0kX1OxopwGQbsIehW/D1X95vajb45APWz5EZx.aJpXEdli';

if (password_verify($password, $hash)) {
    echo "OK";
}
else {
    echo "KO";
}
                    

API de hachage de mots de passe

Options supplémentaires : cost, salt


<?php
$hash = password_hash($password, PASSWORD_DEFAULT, array(
    'cost' => 15,
    'salt' => "mon salt spécifique",
));
                        

Fonctions utilitaires

  • password_get_info()
  • password_needs_rehash()

Compatibilité PHP 5.3 et 5.4 : https://github.com/ircmaxell/password_compat

Déréférencement de tableaux/chaînes


<?php
var_dump( "php"[1] );   // h

var_dump( array(1, 2, 3)[1] );  // 2
var_dump( [1, 2, 3][1] );       // 2

var_dump( [ ['hello', 'plop', 'glop'], [1, 2, 3] ] [0][1] );    // "plop"

// Cas d'erreurs
var_dump( "hello world"["hello"] );   // Illegal string offset 'hello' + 'h'
var_dump( [1, 2, 3][100] );           // Undefined offset: 100 + NULL
                    

::class

Nom pleinement qualifié d'une classe


<?php
use \Plop\Glop\Hello\World as MyClass;

var_dump(MyClass::CLASS);
                    

string(21) "Plop\Glop\Hello\World"
                    

empty()

empty() peut être appelé sur une fonction


<?php
function test_empty() {
    return array();
}

function test_not_empty() {
    return "Hello, World!";
}

if (empty(test_empty())) {
    // ...
}

if (!empty(test_not_empty())) {
    // ...
}
                    

array_column()


<?php
$array = [
    ['a' => 'aa', 'b' => 'bb', 'c' => 'cc'],
    ['a' => 'aaa', 'b' => 'bbb', 'c' => 'ccc'],
    ['a' => 'aaaa', 'b' => 'bbbb', 'c' => 'cccc'],
];

$vals = array_column($array, 'b');
var_dump($vals);
                    

array(3) {
  [0]=>
  string(2) "bb"
  [1]=>
  string(3) "bbb"
  [2]=>
  string(4) "bbbb"
}
                    

array_column()


<?php
$array = [
    ['id' => 123, 'nom' => "Ronnie James Dio"],
    ['id' => 456, 'nom' => "Udo Dirkschneider"],
    ['id' => 789, 'nom' => "Rob Halford"],
];

$noms = array_column($array, 'nom', 'id');
var_dump($noms);
                    

array(3) {
  [123]=>
  string(16) "Ronnie James Dio"
  [456]=>
  string(17) "Udo Dirkschneider"
  [789]=>
  string(11) "Rob Halford"
}
                    

foreach (... as list(...))


<?php
$arr = [
    'premier' => ['aaa', 'bbb'],
    'second' => [123, 456],
];

foreach ($arr as $key => list ($a, $b))
{
    echo "$key => $a, $b\n";
}
                    

premier => aaa, bbb
second => 123, 456
                    

Parfait pour les parcours de tableaux de tableaux.

foreach : clefs non scalaires


<?php
class MyClass {
    public function __construct($val) {
        $this->val = $val;
    }
}
$generator = function () {
    for ($i=0 ; $i<2 ; $i++) {
        yield new MyClass($i) => $i;  // La clef yieldée n'est pas un scalaire
    }
};

foreach ($generator() as $key => $val) {
    var_dump($key, $val);   // La clef n'est pas un scalaire
}
                    

foreach : clefs non scalaires


object(MyClass)#4 (1) {
  ["val"]=>>
  int(0)
}
int(0)

object(MyClass)#5 (1) {
  ["val"]=>
  int(1)
}
int(1)
                    

Iterator::key() peut retourner un non-scalaire.

Impossible d'avoir une clef non-scalaire dans un tableau !

Autres / en vrac

  • Nouveaux itérateurs pour ext/intl
  • hash_pbkdf2()
  • boolval()
  • cli_set_process_title()
  • Mises à jour : libcurl, libgd, libpcre, ...
  • Corrections de bugs / optimisations

Fonctionnalités obsolètes

  • ext/mysql : utilisez ext/mysqli ou PDO !
  • preg_replace() : /e
  • Quelques fonctions/méthodes dans ext/intl et ext/mcrypt

BC-breaks

  • Suppression des GUIDs des logos
  • Arrêt du support de Windows XP et 2003
  • In-sensibilité à la casse désormais indépendante de la locale
  • pack() et unpack() plus proches de Perl
  • Nouveaux mots-clefs, nouvelles fonctions, nouvelles classes

Le futur ?

PHP 5.6 ?

Quelques idées déjà évoquées (rien de défini(tif) !)

  • Structural Type Hinting : dépendance aux méthodes exposées, et plus à une interface nommée
  • Surcharge d'opérateurs pour les classes internes à PHP
  • Corrections / améliorations internes
  • Import de fonctions namespacées

Attention : discussions ne signifie pas fonctionnalités présentes dans une prochaine version !

Quelques liens

Questions ?

PHP 5.5 — AFUP Lyon, 24 juillet 2013 — Pascal MARTIN, @pascal_martin