PHP 7


et évolution de PHP
Nantes, 21 sept. 2015

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

Il était une fois...

8 juin 1995

PHP 1.0

  • Rasmus Lerdorf
  • « Personal Home Page Tools »
  • Orientation Web
  • Ensemble de binaires CGI en C

$ tree php-108


php-108
├── common.c
├── common.h
├── config.h
├── error.c
...
├── README
├── subvar.c
├── version.h
├── wm.c
└── wm.h

0 directories, 18 files
                    

Novembre 1996

PHP/FI 2.0

  • « PHP / Forms Interpreter »
  • 2.0 : seule et unique version stable publiée !

mSQL Functions Demo


<?
    msqlsethost("localhost");
    $name = "bob";
    $result = msql($database,"select * from table where firstname='$name'");
    $num = msql_numrows($result);
    echo "$num records found!<p>";
    $i=0;
    while($i<$num);
        echo msql_result($result,$i,"fullname");
        echo "<br>";
        echo msql_result($result,$i,"address");
        echo "<br>";
        $i++;
    endwhile;
>
                    

Juin 1998

PHP 3.0

  • Andi Gutmans et Zeev Suraski
  • « PHP: Hypertext Preprocessor »
  • À noter :
    • Ré-écriture complète de l'analyseur
    • Mécanisme d'extensions
    • Support Windows, Mac, ...

Pour les curieux

museum.php.net

Mai 2000

PHP 4.0

  • Zend Engine, 1ère version
  • Amélioration performances
  • Fonctionnalités : sessions HTTP, ...
  • Support de + de serveurs Web

Juillet 2004

PHP 5.0

  • Zend Engine 2
  • Nouveau modèle objet
  • 6 versions mineures, sur 10 ans !

PHP 5.x

  • Langage professionnel
  • Applications d'envergure
  • Niveau de qualité qu'on attend en 2015

Migration PHP 4 → 5 difficile

PHP 5.1

Novembre 2005

  • PDO activée par défaut
  • Améliorations gestion des dates
  • Nouvelles fonctions
  • Amélioration des performances

PHP 5.2

Novembre 2006

  • Nouveau gestionnaire de mémoire
  • JSON, Zip, Filter, DateTime
  • Suivi d'upload de fichiers
  • Corrections et améliorations de sécurité
  • Amélioration des performances

PHP 5.3

Juin 2009

  • Espaces de noms
  • Fonctions anonymes, Closures
  • LSB, NOWDOC, ?:, goto, mysqlnd, Garbage Collector, Phar, Intl, Fileinfo, Sqlite3, ...
  • Amélioration des performances

PHP 5.3

Un tournant dans l'utilisation de PHP

Mars 2010

R.I.P. PHP 6

  • Projet ambitieux
  • Pas de réel besoin ?
  • Fonctionnalités backportées sur PHP 5.3
  • Unicode

PHP 5.4

Mars 2012

  • Traits, serveur web de test, sucre syntaxique
  • Suppressions de register_globals, magic_quotes, safe_mode
  • Amélioration des performances, réduction consommation mémoire

Cycle de release

  • Une version mineure par an
  • Deux ans de support
  • + 1 an pour correctifs de sécurité

PHP 5.5

Juin 2013

  • Generators
  • OPcache, finally, ::class, API mots de passe
  • Améliorations syntaxe
  • Fin support Windows XP/2003

PHP 5.6

Août 2014

  • Fonctions variadiques
  • use pour fonctions et constantes
  • Expressions scalaires constantes
  • **, surcharge d'opérateurs (classes internes), phpdbg
supported versions

php.net/supported-versions.php

Statistiques d'utilisation, PHP 5.x

Source : w3techs.com

Une nouvelle version
majeure !

5 + 1 = ?

PHP 6 and MySQL 5 for Dynamic Web Sites: Visual QuickPro Guide

Couverture du livre

PHP 6 Fast and Easy Web Development

Couverture du livre

Professional PHP6 (Wrox Programmer to Programmer)

Couverture du livre

PHP 6/MySQL Programming for the Absolute Beginner

Couverture du livre

PHP6 and MySQL Bible

Couverture du livre
Quelques résultats de recherches

5 + 1 = 6 7

Une nouvelle version
majeure !

PHP, espace, 7

logo PHP 7

PHP 7

Les nouveautés

Gestion d'erreurs

Erreurs → exceptions

  • Une partie des erreurs Fatales
  • internes à / levées par PHP
  • sont transformées en Error
  • qui peuvent être catchées

Erreurs → exceptions


<?php
$obj = null;
try {
    // Ooops !
    $obj->methode();
}
catch (Error $e) {
    var_dump($e->getMessage());
}
?>
                    

string(43) "Call to a member function methode() on null"
                    

Erreurs → exceptions


<?php
$php = <<<'PHP'
$a = 10        // -- Parse error ! -- //
printf("\$a = %d\n", $a);
PHP;

try {
    eval($php);
}
catch (ParseError $e) {
    var_dump($e->getMessage());
}
?>
                    

string(44) "syntax error, unexpected 'printf' (T_STRING)"
                    

Erreurs → exceptions


echo "Fichier 1 - avant\n";
try {
    // Fichier avec une erreur de syntaxe
    include __DIR__ . '/test-06-2.php';
}
catch (Error $e) {
    echo "Error catchée : ";
    var_dump($e->getMessage());
}
echo "Fichier 1 - après\n";
                    

Fichier 1 - avant
Error catchée : string(42) "syntax error, unexpected '$b' (T_VARIABLE)"
Fichier 1 - après
                    

Erreurs → exceptions

Hiérarchie d'erreurs / exceptions


interface Throwable
    Exception implements Throwable
        // Toutes les exceptions usuelles
    Error implements Throwable
        AssertionError extends Error
        ParseError extends Error
        TypeError extends Error
                    

Erreurs → exceptions

  • Une partie des erreurs Fatales
  • internes à / levées par PHP

Type hints scalaires

Type hints scalaires


<?php
function add(int $a, int $b) {
    return $a + $b;
}
                    

var_dump( add(10, 20) );
var_dump( add('10', '20') );
                    

int(30)
int(30)
                    

Type hints scalaires


try {
    var_dump( add(10, 'abc') );
}
catch (TypeError $e) {
    var_dump( $e->getMessage() );
}
                    

string(148) "Argument 2 passed to add()
    must be of the type integer, string given,
    called in .../test-01.php on line 12"
                    

Types de retour


function add(int $a, int $b) : int {
    return $a + $b;
}
                    

Types de retour


function get_config() : array {
    return 42;
}
get_config();
                    

Fatal error: Uncaught TypeError:
    Return value of get_config() must be
    of the type array, integer returned
                    

Typage strict


<?php
declare(strict_types=1);

function add(int $a, int $b) {
    return $a + $b;
}

add(10, '20');
                    

Fatal error: Uncaught TypeError:
    Argument 2 passed to add()
    must be of the type integer, string given
                    

Souple / Strict ?

  • Paramètres : au choix de l'appelant
    • Sait si il manipule des types souples ou stricts
  • Retour : au choix de l'appelé
    • Sait si la fonction qu'il a écrite utilise des types souples ou stricts

Souple / Strict ?

  • Les données sont des types indiqués.
  • Détermine si des conversions sont ou non permises.

Null Coalesce Operator


$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
                    

$username = $_GET['user'] ?? 'nobody';
                    

$model = Model::get($id) ?? $default_model;
                    

function foo() {
    echo "executed!", PHP_EOL;
}
var_dump(true ?? foo());
                    
TIE Fighter

Dans peu de temps, dans notre galaxie...

Not this TIE Fighter ;-)

Not this TIE Fighter ;-)

<=>

Combined Comparison (Spaceship) Operator


function order_func($a, $b) {
    return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
}
                    

function order_func($a, $b) {
    return $a <=> $b;
}
                    

<=>

Ou avec des tableaux


function order_func($a, $b) {
    return ($a->$x <=> $b->x) ?:
        ($a->y <=> $b->y) ?:
        ($a->foo <=> $b->foo);
}
                    

function order_func($a, $b) {
    return [$a->x, $a->y, $a->foo]
        <=> [$b->x, $b->y, $b->foo];
}
                    

Classes anonymes

Classes anonymes


$obj = new class ("Monde") {
    protected $qui;

    public function __construct($qui) {
        $this->qui = $qui;
    }

    public function hello() {
        printf("Hello, %s !\n", $this->qui);
    }
};

var_dump($obj);
$obj->hello();
                    

Classes anonymes


object(class@anonymous)#1 (1) {
  ["qui":protected]=>
  string(5) "Monde"
}
Hello, Monde !
                    

Classes anonymes

Quelle utilité ?

  • Usage unique
  • Pas besoin de documentation
  • On verra ;-)

Classes anonymes

Exemples ?

  • Logger
  • SplObserver, avec SplSubject
  • + qu'une fonction anonyme

Amélioration de assert()

assert()


$a = 20;
assert($a == 10, "Echec assertion !");
printf("a = %d\n", $a);
                    

Warning: assert(): Echec assertion !
                    

assert()

assert.exception = 1


try {
    assert($a == 10);
}
catch (AssertionError $e) {
    var_dump($e);
}
                    

assert()

zend.assertions

  • 1 : activées (dev)
  • 0 : non exécutées
  • -1 : non compilées (prod)

Regrouper les
déclarations use

Group use declarations


use Mon\Espace\De\Nom\ClasseAa;
use Mon\Espace\De\Nom\ClasseBb;
use Mon\Espace\De\Nom\ClasseCc;
use Mon\Espace\De\Nom\Enfant\AutreClasse as ClassDd;
                    

use Mon\Espace\De\Nom\ {
    ClasseAa, ClasseBb, ClasseCc,
    Enfant\AutreClasse as ClassDd
};
                    

Group use declarations


use function Mon\Nom\fonc01;
use const Mon\Nom\CONST01;
use Mon\Nom\Class01;
                    

use Mon\Nom\ {
    function fonc01,
    const CONST01,
    Class01
};
                    

Améliorations sécurité

Secure unserialize


$data = unserialize($serialized, [
    "allowed_classes" => false
]);
                    

$data = unserialize($serialized, [
    "allowed_classes" => [
        MaClasse::class,
        'MonAutreClasse',
    ]
]);
                    

Nombres aléatoires


var_dump( random_int(10, 100) );
var_dump( bin2hex(random_bytes(12)) );
                    

int(23)
string(24) "903c636403869d3c3ab3310e"
                    

JSON

  • Extension jsond
  • Option JSON_PRESERVE_ZERO_FRACTION pour json_encode()

var_dump( json_encode(42.0) );
var_dump( json_encode(42.0, JSON_PRESERVE_ZERO_FRACTION) );
                    

string(2) "42"
string(4) "42.0"
                    

Unicode et Intl

  • Classe IntlChar
  • Caractères unicodes

echo "Des chats : \u{1F638} \u{1F639} \u{1F63A}\n";
                    

Des chats : 😸 😹 😺
                    

Generators et return


function plop() {
    yield 100;
    yield 200;
    return 42;
}

foreach (($generator = plop()) as $val) {
    var_dump($val);
}

var_dump( $generator->getReturn() );
                    

int(100)
int(200)
int(42)
                    

Generator Delegation


function test() {
    yield from [10, 20, 30];
}

foreach (test() as $val) {
    var_dump($val);
}
                    

int(10)
int(20)
int(30)
                    

Generator Delegation


function sub_generator_1() {
    yield 10;
    yield 20;
}
function sub_generator_2() {
    yield from [ 'aa', 'bb', ];
}
function delegating_generator() {
    yield from sub_generator_1();
    yield from sub_generator_2();
}

foreach (delegating_generator() as $val) {
    var_dump($val);
}
                    

int(10)
int(20)
string(2) "aa"
string(2) "bb"
                    

Et encore

  • intdiv()
  • Closure::call()

Processus
d'évolution
de PHP

Open-Source

  • Pas « Zend » uniquement !
  • Y compris pour les décisions
  • Méritocratie ? Démocratie ?
  • Pas de BDFL

Nombre de commits

Nombre de commits

"Top" depuis le début

Top contributeurs depuis le début

"Top" depuis Sept 2012

Top contributeurs depuis octobre 2012

Espaces d'échanges

  • internals@
  • Des RFCs
  • Un processus de votes
  • Twitter, reddit, blog-posts, ... non officiels !

internals@

  • Mailing-list des développeurs de PHP
  • Discussions autour du développement de PHP
  • Active depuis 1997
  • Publique
  • Quelques centaines de mails par mois. Ou plus.

Pas tant de trolls que ça,
en fait !

RFC ?

  • Formalisation des éventuels changements
  • Idée + implémentation
  • Template pour présenter une proposition
  • Principe apparu vers PHP 5.3

Moi, certains matins ^^

Assez calme, en ce moment.

Discussions

  • Échanges sur internals@
  • Avant de créer une RFC ?
  • Autour d'une RFC
  • Pendant la phase de votes

Points de vue

  • Conservateurs
  • Progressistes
  • Égoistes ?
  • ...

Points de vue

  • Développeurs de fonctionnalités
  • Utilisateurs de PHP
  • Mainteneurs de PHP
  • ...

Points de vue

  • Stabilité vs BC-breaks vs évolution
  • Langage complet vs accessible
  • Sujets sensibles
    • Typage souple vs strict
    • Langage dynamique vs statique
    • Annotations
    • Façon de procéder : procédures vs comme avant
    • ...

Votes

  • Par défaut : 50%+1
  • Modification du langage : 2/3
  • Min. 2 semaines après RFC
  • Qui peut voter ?
  • Durée des votes ?

Et à l'AFUP ?

Et à l'AFUP ?

  • Une mailing-list
  • Des discussions
  • Un post sur internals@
  • Un blog-post

AFUP

php-internals@afup.org

AFUP

1300+ mails depuis août 2014 !

AFUP

~50 avis sur internals@

AFUP

php-internals.afup.org

La communauté

En fait...

logos outils

Pas une communauté, mais plusieurs

En fait...

  • Plusieurs types de développeurs
    • Débutants

En fait...

  • Plusieurs types de développeurs
    • Débutants
    • Amateurs
    • Utilisateurs et intégrateurs de logiciels
    • Développeurs (PHP) full-time
    • Hébergeurs

En fait...

  • Des besoins très différents
  • Certains s'expriment plus que d'autres
The vast majority of the PHP community never ever interacts with internals@, never attend conferences, don't write blog posts about PHP and are generally completely 'under the radar'.

Zeev Suraski

Vous !

Un petit jeu ;-)

  • Combien de collègues développeurs PHP ?
  • Combien faisaient de la veille ?
  • Combien suivaient le développement de PHP ?
  • Combien participent à des événements communautaires ?
  • Combien sont membres AFUP ?

Vous !

Même question, avec utilisateurs de PHP, sans se limiter à un cadre profesionnel.

La communauté

Sommes-nous représentatifs de la majorité des utilisateurs de PHP ?

I would actually go to argue that the people who do attend conferences, participate on internals@ or write blog posts - are not representative of the PHP userbase at large.

Zeev Suraski

PHP 7

Une nouvelle version
majeure !

PHP 7

Les suppressions

Ménage !

Suppression des fonctionnalités obsolètes

  • Assignment of new by reference
  • set_magic_quotes_runtime() et magic_quotes_runtime()
  • dl() on fpm-fcgi
  • Scoped calls of non-static methods from incompatible $this context

Ménage !

Suppression des fonctionnalités obsolètes

  • Directives ini d'encodage pour mbstring et iconv
  • Commentaires en # dans les fichiers .ini
  • Paramètre $is_dst de mktime() et gmmktime()
  • Directive ini xsl.security_prefs
  • Série d'autres fonctions

Ménage !

Suppression des fonctionnalités obsolètes

  • Uploads curl non-sûrs
  • Modificateur /e de preg_replace()
  • Noms de catégories sous forme de chaînes de caractères pour setlocale()
  • ...

Ménage !

Suppression d'extensions

  • ext/ereg → PCRE
  • ext/mysqlmysqli

Enfin !

Ménage !

Suppression d'extensions

  • ext/mssql
  • ext/sybase_ct

ext/imap et ext/mcrypt ont été conservées, mais sont basées sur des bibliothèques non maintenues !

Ménage !

Suppression de SAPIs

  • sapi/aolserver
  • sapi/apache
  • sapi/apache_hooks
  • sapi/apache2filter
  • sapi/caudium
  • sapi/continuity
  • sapi/isapi

Ménage !

Suppression de SAPIs

  • sapi/milter
  • sapi/phttpd
  • sapi/pi3web
  • sapi/roxen
  • sapi/thttpd
  • sapi/tux
  • sapi/webjames

PHP 7

La cohérence du langage

Tags alternatifs

Supprimés !

  • <% et <%= ... %>
  • Directive asp_tags
  • <script language="php"> ... </script>

<? et <?= sont conservés !

Lexer contextualisé


class Query {
    public function where() { return $this; }
    public function and() { return $this; }
    public function or() { return $this; }
    public function not() { return $this; }
}

$obj = new Query();
$obj->where('condition')
    ->or('autre condition')
    ->and()->not('encore');
                    

switch + >1 default


switch (10) {
    default:
        var_dump("premier default");
        break;
    default:
        var_dump("second default");
        break;
}
                    

Fatal error: Switch statements may only contain one default clause
                    

Mots réservés

Usage interdit en tant que :

  • Classe
  • Trait
  • Interface
  • Espace de nom

Mots réservés

  • int
  • float
  • bool
  • string
  • true et false
  • null

Mots réservés

  • resource
  • object
  • scalar
  • mixed
  • numeric

Mais aussi

  • Constructeurs façon PHP 4E_DEPRECATED
  • Erreurs E_STRICT transformées en E_DEPRECATED ou E_NOTICE ou E_WARNING
  • Arrêt du support des nombres hexa dans chaînes : "OxAB"

Mais aussi

  • Cohérence pour list() et chaînes
  • Cohérence pour foreach()
  • Output buffering utilisable en cas d'abandon de connexion

Mais aussi

  • Arbre syntaxique (AST) utilisé pour la compilation
  • Constructeurs de classes internes
  • Comportement cross-plate-formes identique pour les entiers
  • Parse error sur numériques invalides : 0891

À propos d'entiers


mt_rand(0, 9.0E21);
srand(9.0E21);
                    

Avec PHP 5.6 :


Warning: mt_rand(): max(-2011107970261188608) is smaller than min(0)
                    

Avec PHP 7.0 :


Warning: mt_rand() expects parameter 2 to be integer, float given
Warning: srand() expects parameter 1 to be integer, float given
                    

Variables : syntaxe uniforme

  • Syntaxe cohérente et complète
  • Permet de nouvelles écritures
  • Mais change / casse certaines syntaxes rarement utilisées

Variables : syntaxe uniforme


function plop() {
    return [
        'a' => 'aaa',    // Nom d'une fonction
        'b' => 'bbb',
        'c' => 'ccc',
    ];
}

function aaa() { var_dump(__FUNCTION__); }    // La fonction
function bbb() { var_dump(__FUNCTION__); }
function ccc() { var_dump(__FUNCTION__); }

$fonction = 'plop';

$fonction()['a']();
                    

Variables : syntaxe uniforme


class MaClasse {
    public $propriete;

    public function __construct($val) {
        $this->propriete = $val;
    }
}

$a = new MaClasse(42);
$b = new MaClasse(123);

var_dump( [ $a, $b ][0]->propriete );
                    

Variables : syntaxe uniforme


class MaClasse {
    public function maMethode() {
        var_dump(__METHOD__);
    }
}

$obj = new MaClasse();

[ $obj, 'maMethode' ]();
                    

Variables : syntaxe uniforme


class MaClasse {
    public static function maMethode() {
        var_dump(__METHOD__);
    }
}

$methode = 'maMethode';

'MaClasse'::$methode();
                    

Variables : syntaxe uniforme

Appel d'une fonction anonyme


function ma_fonction() {
    var_dump(__FUNCTION__);
}

( function () {
    return 'ma_fonction'();
})();
                    

Variables : syntaxe uniforme

Écriture désormais invalide :


global $$foo->bar;
                    

À remplacer par :


global ${$foo->bar};
                    

Variables : syntaxe uniforme

Changements


// écriture          // PHP 5               // PHP 7
$$foo['bar']['baz']  ${$foo['bar']['baz']}  ($$foo)['bar']['baz']
$foo->$bar['baz']    $foo->{$bar['baz']}    ($foo->$bar)['baz']
$foo->$bar['baz']()  $foo->{$bar['baz']}()  ($foo->$bar)['baz']()
Foo::$bar['baz']()   Foo::{$bar['baz']}()   (Foo::$bar)['baz']()
                    

PHP 7

Les performances !

phpng

Ensemble d'améliorations internes orientées performances

bench.php

Graphe bench.php

Wordpress

Graphe bench.php

Optimisations mémoire

  • zval : 24 → 16 octets
  • Hashtable : 76 → 56 octets
  • Entrée de Hashtable : 72 → 32 octets
  • Optimisation sur tableaux immuables
  • Nouvel allocateur mémoire

Optimisations CPU

  • Fast ZPP
  • API itération hashtable + rapide
  • JIT PCRE activé par défaut
  • Conversion de certaines fonctions en opcodes : strlen(), is_*(), defined()
  • ...

OPcache en fichiers

--enable-opcache-file


; php.ini
opcache.file_cache=/var/tmp
                    

; php-cli.ini
opcache.enable_cli=1
opcache.file_cache=/var/tmp
opcache.file_cache_only=1


                    

Performances

Sur applications réelles

  • 50% à 100% supérieures à PHP 5.6
  • Proches de celles de HHVM 3.7
  • Consommation mémoire diminuée

PHP 7

Mais pas...

Named Parameters

Ne spécifier que les paramètres utiles


htmlspecialchars($string, double_encode => false);
                    

Ou juste s'y retrouver


strpos(hasytack => "foobar", needle => "bar");
                    

Loop... or


while ($cond) {
    // loop body
}
or {
    // did not enter while loop
}
                    

Static classes

Classe non instanciable, uniquement des méthodes statiques


static class Environment
{
    private static $rootDirectory = '/var/www/project';
    public static function getRootDirectory()
    {
        return self::$rootDirectory;
    }
}
                    

Using objects as keys


class Plop {
    public function __hash() {
        return 'une chaine'; // ou un entier
    }
}

$obj = new Plop();
$array = [
    $obj => "une valeur",
];

                    

Parameter skipping


// Dernier param vaut true par défaut
// On spécifie les valeurs par défaut
// pour les deux paramètres précédents
echo htmlspecialchars("plop",
    ENT_COMPAT | ENT_HTML401,
    ini_get("default_charset"),
    false
);
                    

Aurait pu devenir


echo htmlspecialchars("plop", default,
                      default, false);
                    

Threads / Async

Pas la façon de faire de PHP

  • Threads : Extension pthreads
  • Async : ReactPHP, Icicle

JIT

Pas pour PHP 7.0

PHP 7

Et la migration  ?

Elle devrait plutôt bien se passer !

Objectif

Plus rapide que PHP 4 → PHP 5

Compatibilité

  • Pas de gros changement
  • Modifications (cohérence) sur des points de syntaxe peu utilisés
  • Suppression de fonctionnalités obsolètes depuis longtemps

Documentation

php.net/migration70

Les extensions ?

github.com/gophp7/gophp7-ext/wiki/extensions-catalog

Pour tester ?

Un exemple ?

Tests atoum

  • Durée divisée par 1.6
  • 2 tests KO
  • Dont un à cause d'une extension non installée !

Vos applis ?

  • Testez !
  • Signalez les problèmes ;-)

Rappels

  • EOL de PHP 5.6 approche
  • Gains de performances
  • Fonctionnalités
  • Source de motivation pour vos développeurs ?

C'est encourageant !

Et encore ?

Futur ? De PHP 7 ?

  • PHP 7.1

$ $HOME/bin/php-7.0/bin/php --version
PHP 7.1.0-dev (cli) (built: Sep 20 2015 10:48:32)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0-dev, Copyright (c) 1998-2015 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies
                    
  • PHP 7.x ?
  • PHP 8 ?

Forum PHP

event.afup.org/forum-php-2015

23 et 24 novembre 2015

Track spéciale PHP 7 !

Participez !

  • Du code, des tests, des PRs
  • Testez PHP 7
  • Postez vos retours d'expérience
  • Améliorez la doc

La documentation

Documentation des générateurs

La documentation

Documentation des générateurs : contribuer

La documentation

Documentation des générateurs : contribuer

Contribuez !

Qui suis-je ?

Questions ?