Meetup PHP 7.x

Marseille/Aix, 21 février 2017

Montpellier, 22 février 2017

Meetup PHP 7.x

Marseille/Aix, 21 février 2017

Meetup PHP 7.x

Montpellier, 22 février 2017

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

Utilisez la touche [ESPACE]
pour passer au slide suivant.

On en est où ?

  • PHP 5.6
    • Publiée le 28 août 2014
    • Dernière version 5.x
  • PHP 7.0
    • Publiée le 3 décembre 2015
  • PHP 7.1
    • Publiée le 1er décembre 2016

PHP, espace, 7

logo PHP 7

Versions supportées

Supported Versions

php.net/supported-versions.php

Statistiques d'utilisation, PHP 5.x

Source : w3techs.com

Statistiques d'utilisation, PHP

Source : w3techs.com

Cycle de releases

Depuis PHP 5.4

  • 1 version mineure tous les ans
  • 2 ans de support
  • + 1 an de support de sécurité

Support de sécurité allongé pour PHP 5.6

Avant

Quelques rappels ?

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;
>
                        

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 2010 et plus

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, NOWDOW, ?:, goto, mysqlnd, Garbage Collector, Phar, Intl, Fileinfo, Sqlite3
  • Amélioration des performances

PHP 5.3

Un tournant dans l'utilisation de PHP

Logo Composer

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

PHP 5.5

Juin 2013

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

PHP 5.5

Generators

blog.pascal-martin.fr/post/php-semaine-des-generateurs.html

PHP 5.6

Août 2014

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

Une nouvelle version majeure ?

  • 10 ans de PHP 5.x
  • Performances : limite du moteur PHP 5 atteintes
  • Besoin marketing
  • Possibilité de casser des choses
  • Des nouveautés !

PHP 6 \o/

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

PHP 7.0

Les nouveautés

Null Coalesce Operator


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

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

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

Unicode Codepoint Escape Syntax


$ php -r 'echo "I \u{2665} PHP!\n";'
I ♥ PHP!
	                    

$ php -r 'echo "\u{1F408} \u{1F431} \u{1F638} \u{1F639} \u{1F63A} \u{1F63B} \u{1F63C} \u{1F63D} \u{1F63E} \u{1F63F} \u{1F640} - so cute!!!\n";'
🐈 🐱 😸 😹 😺 😻 😼 😽 😾 😿 🙀 - so cute!!!
	                    

Type hints scalaires


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


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.

Combined Comparison (Spaceship) Operator


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

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

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
};
	                    

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


$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'
$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

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


$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 !
	                    

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) {
    // Travail avec $val
}
	                    

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"
                        

Bonus

  • Migration PHP 5.6 → 7.0 assez facile
  • Performances ++

bench.php

Graphe bench.php

Wordpress

Graphe bench.php
Graphe bench.php

talks.php.net/afup15

Graphe bench.php

talks.php.net/afup15

Tweet
Tweet
Tweet
Tweet
Tweet
Tweet
Tweet

Mais comment ?

Pour en savoir plus sur les changements internes :

PHP 7 – What changed internally? - Nikita Popov - Forum PHP 2015

PHP 7.1

Les nouveautés

Class Constant Visibility


class MaClasse {
    public const MA_PUBLIQUE = 42;
    private const MA_PRIVEE = 1234;
    public function test() {
        var_dump( self::MA_PRIVEE );
    }
}
						

var_dump( MaClasse::MA_PUBLIQUE ); // int(42)
(new MaClasse())->test(); // int(1234)
						

// Error: Cannot access private const MaClasse::MA_PRIVEE
var_dump( MaClasse::MA_PRIVEE );
	                    

Allow specifying keys in list()


$array = [
    'glop' => "Hello",
    'plop' => 123456,
    'who' => "World",
];
	                    

list (
    'glop' => $a,
    'who' => $b
) = $array;
	                    

var_dump($a, $b);
// string(5) "Hello"
// string(5) "World"
	                    

[] for array destructuring assignment


[$a, $b] = [10, 20];
var_dump($a, $b);
// int(10)
// int(20)
	                    

['glop' => $glop, 'plop' => $plop] = [
    'plop' => 42,
    'glop' => "Hello",
];
var_dump($plop, $glop);
// int(42)
// string(5) "Hello"
	                    

Generalize support of negative string offsets


$str = "Pascal";
var_dump($str[2]);  // string(1) "s"
var_dump($str[-2]); // string(1) "a"
	                    

Generalize support of negative string offsets


$str = "Pas.al";
$str[-3] = 'c';
var_dump($str);  // string(6) "Pascal"
	                    

Generalize support of negative string offsets


var_dump( strpos("Pascal", "c", -5) ); // int(3)
	                    

Catching Multiple Types


class Plop extends Exception {}
class Blah extends Exception {}
class Another extends Exception {}
	                    

try {
    switch (mt_rand(0, 2)) {
        case 0: throw new Plop();
        case 1: throw new Blah();
        case 2: throw new Another();
    }
} catch (Plop | Blah $e) {
    printf("1er catch : %s\n", get_class($e));
} catch (Another $e) {
    printf("2nd catch : %s\n", get_class($e));
}
	                    

Throw Error in Extensions

La majorité des erreurs fatales levées par des extensions intégrées à PHP sont converties en exceptions.

Nullable Types

PHP 7.0


function fonc01(int $a) {
    var_dump($a);
}
	                    

fonc01(100); // int(100)

fonc01(null); // TypeError: Argument 1 passed to
              // fonc01() must be of the type
              // integer, null given
	                    

Nullable Types

PHP 7.1


function fonc01(?int $a) {
    var_dump($a);
}
	                    

fonc01(100); // int(100)
fonc01(null); // NULL
	                    

fonc01();
// Error: Too few arguments to function fonc01(), 0 passed
	                    

Nullable Types


function fonc02(?int $a, ?int $b) : ?int {
    if ($a === null || $b === null) {
        return null;
    }
    return $a + $b;
}
	                    

var_dump( fonc02(10, 20) ); // int(30)
var_dump( fonc02(10, null) ); // NULL
	                    

Void Return Type


function fonc01() {
    printf("%s\n", __FUNCTION__);
}
	                    

function fonc02() : void {
    printf("%s\n", __FUNCTION__);
}
	                    

function function03() : void {
    printf("%s\n", __FUNCTION__);

    // Fatal error: A void function must not return a value
    return 'plop';
}
	                    

Iterable


function fonc01(iterable $data) {
    foreach ($data as $key => $val) {
        // ...
    }
}
	                    

fonc01( [10, 20, 30] );
fonc01( new SplFixedArray(5) );
fonc01( mon_generateur() );
	                    

Closure::fromCallable()


function ma_fonction() {
    var_dump(__FUNCTION__);
}
	                    

$closure = Closure::fromCallable('ma_fonction');
$closure();  // string(11) "ma_fonction"
	                    

$closure = Closure::fromCallable('plop');
// TypeError: Failed to create closure from callable:
// function 'plop' not found or invalid function name
	                    

Bref, PHP 7.1

  • Sortie il y a trois mois
  • La version stable actuelle
  • Des améliorations par rapport à 7.0
  • La version à utiliser ;-)
  • Quitte à sauter 7.0

Points douloureux ?

Une nouvelle version
majeure !

Migration facile

Assez peu de bc-breaks

Mais quand même.

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

On sait jamais ^^

  • resource
  • object
  • scalar
  • mixed
  • numeric

Tags alternatifs

Supprimés !

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

<? et <?= sont conservés !

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 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 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

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
                        

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"

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']()
                        

Casse Magento 1.x ;-)

Des bc-breaks en PHP 7.1 ?

Oui...

Chaines et arithmetique invalide


var_dump('10 apples' + '5 oranges');
// Notice: A non well formed numeric value encountered in .../01-warn-invalid-string-arithmetic.php on line 7
// Notice: A non well formed numeric value encountered in .../01-warn-invalid-string-arithmetic.php on line 7
// int(15)
                        

var_dump(10 + "plop");
// Warning: A non-numeric value encountered in .../01-warn-invalid-string-arithmetic.php on line 12
// int(10)
                        

Missing argument


function my_function($a, $b) { ... }
my_function(10);
                        

PHP <= 7.0
    Warning: Missing argument 2 for my_function(),
        called in ... and defined in ...
    int(10)
    NULL
                        

PHP >= 7.1
    Fatal error: Uncaught Error: Too few arguments to function my_function(),
        1 passed in ... and exactly 2 expected in ...
                        

Et toujours 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");
                        

Bah non.

Loop... or


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

Non plus.

Threads / Async

Pas la façon de faire de PHP.

  • Threads : Extension pthreads
  • Async : ReactPHP, Icicle

Comment migrer ?

  • Le poste de dev d'une personne motivée
  • Analyse statique : php7cc, phan
  • Tests automatisés
  • Tests manuels
  • Dupliquer le trafic de la prod ?

En fait...

Exactement comme pour n'importe quelle autre montée de version !

Et après ?

Cycle de releases

  • 1 version mineure par an
  • PHP 7.2 en fin d'année 2017 ?
  • 1 version majeure évoquée
  • PHP 8.0 un jour ?

PHP 7.2

Travail tout juste commencé, mais déjà une bonne dizaine de RFCs acceptées ;-)

PHP 7.2

  • Add session_gc(), session_create_id()
  • E_WARNING for invalid container array-access
  • Argon2 Password Hash
  • get_class() disallow null parameter
  • Counting of non-countable objects

Invalid container array-access


$var = false;
$var[1][2][3][4][5];
// This will throw a single E_WARNING, as accessing ($a[1])[2]
// is attempting to access a IS_VAR chain that is NULL.
                        

$var = array(123);
$var[0][1];
// This will throw an E_WARNING, as accessing $a[0] is valid
// [1] is accessing an integer as an array.
                        

PHP 7.2

  • Deprecate png2wbmp() and jpeg2wbmp()
  • Convert numeric keys in object/array casts
  • Debugging PDO Prepared Statement Emulation v2
  • Parameter Type Widening
  • HashContext as Object

PHP 7.2

  • Trailing commas in all list syntax (partiel)
  • Deprecate and remove INTL_IDNA_VARIANT_2003
  • Libsodium
  • Deprecations for PHP 7.2
  • ...

PHP 8.0

Pour l'instant, à peine évoqué comme cible d'évolutions ou refontes.

Surtout cible de quelques suppressions et bc-breaks, anticipés dès PHP 7.1 et 7.2 par j'ajout de E_DEPRECATED.

Futures suppressions

  • Deprecate mb_ereg_replace() eval option
  • Deprecate (then Remove) Mcrypt
  • Deprecate png2wbmp() and jpeg2wbmp()

Les six-huit prochains mois vont être intéressants !

The end.

Presque ;-)

Participez !

  • Du code, des tests, des PRs
  • Passez à PHP 7 !
  • Partagez votre retour d'expérience

PHP Tour

event.afup.org

18 et 19 mai, Nantes

L'appel à conférenciers et conférencières est encore ouvert ;-)

La documentation

Documentation des générateurs

La documentation

Documentation des générateurs : contribuer

La documentation

Documentation des générateurs : contribuer

Contribuez !

Pascal MARTIN

blog.pascal-martin.fr
contact@pascal-martin.fr
@pascal_martin

php7avance.fr — @php7avance