PHP 7.1 : la route vers PHP 7.2 et PHP 8.0

15 septembre 2016 php, php-7.1

This post is also available in English.
Ceci est le dixième article d’une série à propos de PHP 7.1.


PHP 7.1 n’est que la seconde version mineure de la branche PHP 7, mais les esprits commencent déjà à penser à la suite : la version mineure suivante, PHP 7.2 ; et la prochaine version majeure, ce qui pourrait être PHP 8.0.


Des suppressions pour PHP 8.0

Il ne s’agit pas encore de réflexions très profondes dans le cœur du moteur, mais de commencer dès maintenant à ajouter quelques E_DEPRECATED ou E_NOTICE sur des fonctionnalités déconseillées de PHP 7.x, en vue de les supprimer pour PHP 8.0.

Option eval de mb_ereg_replace()

Le modificateur /e de la fonction preg_replace() a été supprimé avec PHP 7.0 (‣RFC), mais il est resté pour la fonction mb_ereg_replace().

Pour uniformiser, utiliser ce modificateur dangereux en PHP 7.1 pour les fonctions mb_ereg_replace() et mb_eregi_replace() lèvera désormais un avertissement de niveau E_DEPRECATED.

À la place, passez par la fonction mb_ereg_replace_callback().

Ce modificateur devrait ensuite être supprimé, pour PHP 8.0.

‣ La RFC : Deprecate mb_ereg_replace() eval option


La fin de mcrypt ?

L’extension mcrypt est basée sur une bibliothèque qui n’est plus maintenue depuis des années — ce qui est quelque peu problématique, considérant qu’elle est fortement liée à la sécurité !

Au moment de PHP 7.0, il avait donc été proposé de supprimer cette extension de PHP. Mais beaucoup de développeurs l’utilisant encore, cela n’avait finalement pas été fait.

Pour laisser plus de temps aux développeurs et rendre la migration moins abrupte, l’extension mcrypt sera marquée comme obsolète à partir de PHP 7.1 : l’utiliser mènera à des avertissements de niveau E_DEPRECATED.

L’extension mcrypt devrait ensuite être supprimée pour PHP 8.0.

‣ La RFC : Deprecate (then Remove) Mcrypt


Et pour PHP 7.2 ?

La sortie de PHP 7.1 approchant, cela fait plusieurs mois qu’il n’est plus possible d’ajouter de nouvelle fonctionnalité pour cette version.

Sans surprise, plusieurs idées ont déjà commencé à être évoquées, pour ce qui pourrait devenir la version suivante : PHP 7.2.


Vous trouverez ci-dessous quelques RFC correspondant à certaines de ces idées.

Comme toujours, quelques-unes d’entre elles iront jusqu’au processus de votes, une partie seulement seront acceptées, alors qu’un nombre important seront finalement oubliées :

Je me permets d’insister encore une fois : ce n’est pas parce qu’une RFC a été rédigée que l’idée correspondante mènera à une nouveauté pour PHP !


PHP 7.1 : et bien non !

15 septembre 2016 php, php-7.1

This post is also available in English.
Ceci est le neuvième article d’une série à propos de PHP 7.1.


J’ai parlé ces derniers jours de plusieurs évolutions que nous retrouverons bientôt dans PHP 7.1. Cela dit, sur environ un an de durée de développement, de nombreuses autres idées ont été évoquées, de nombreuses autres RFCs ont été rédigées.

Certaines de ces RFCs sont arrivées jusqu’à la phase de votes et ont été rejetées, d’autres n’ont pas été jusqu’au bout du processus, certaines ont pu être annulées au profit d’autres… Bref, de nombreux points ont été discutés sans pour autant passer et je vais essayer d’en dresser une très rapide liste ici.

Pour commencer, voici quelques RFCs rejetées ou annulées, qui retiennent mon attention lorsque je relis leurs titres :

Et voici d’autres points qui ont été discutés, mais sans que les RFCs correspondantes n’aillent jusqu’au vote (je crois) ; et donc, qui ne sont ni passés ni rejetés :

Certaines de ces propositions étaient intéressantes… Et même si la plupart d’entre elles ne reviendront pas sur le devant de la scène tout de suite, il est probable que quelques-unes seront rediscutées dans le futur !


PHP 7.1: a few other things

September 14, 2016 php, php-7.1, english

Cet article est aussi disponible en français.
This is the 8th post in a series about PHP 7.1.


After a year of work, evolutions brought by PHP 7.1 are not limited to those I presented these past few days!

Here’s the rest of the list, grouping in this post pretty-much all remaining new features, even if they didn’t really catch my eye for now — but might still be of interest to some of you?


Asynchronous Signal Handling

Until PHP 7.1, dealing with signals with the pcntl extension required us to call pcntl_signal_dispatch() by hand, synchronously, or to use declare(ticks=1) — with a non-negligible impact on execution.

We use PHP more and more in command line or for long scripts, in which cases we must often deal with signals efficiently, as they are a rather typical inter-process communication mean. To answer this need, we can now, with PHP 7.1, handle signals asynchronously, thanks to the new pcntl_async_signals() function.

pcntl_async_signals(true);

pcntl_signal(SIGTERM, function ($signo) {
    var_dump("SIGTERM"); die;
});

while (true) {
    usleep(100);
}

Sending a TERM signal to our process (via kill 31321 and adapting the PID ;-)) will cause the execution of the callback function, which in this example displays the name of the signal and ends the script.

The pcntl.async_signals configuration directive, which defaults to 0, allows us to systematically enable this behavior, without having to call pcntl_async_signals(true). This default value will probably change in a future version of PHP.

‣ The: Asynchronous Signal Handling


Octal overflow detection

With PHP, we can include a byte in a string, using its octal representation:

$str = "Un caractère : \123";
var_dump($str);
// string(17) "Un caractère : S"

But, for this representation to really fit in one byte, its firts digit must be between 0 and 3. A higher digit will cause an overflow: "\400" will actually correspond to "\000", "\500" will be interpredted as "\100" and so on. This means the following piece of code results in the same output as the previous one:

$str = "Une tentative : \523";
var_dump($str);
// string(17) "Une tentative : S"

This overflow was silent with PHP 7.0. Now, with PHP 7.1, the behavior remains the same but a warning will be raised, indicating the developer she wrote something odd:

Warning: Octal escape sequence overflow \523 is greater than \377 in .../demo-01.php on line 12

‣ The RFC: Octal overflow detection


And some other stuff, if you are curious

Finally, and presented as-is, here are the other RFCs which passed and will bring new features for PHP 7.1 — I won’t be giving any example nor present them more in detail:

These evolutions shouldn’t have much impact on your application, but could still be helpful in some situations — like allowing for a more precise representation of floatting-point values or beginning introducing support for HTTP/2.


The end of this series is getting near, but I still have a few points I want to write about.
Tomorrow, we’ll see a list of ideas which have been mentionned during the development cycle of PHP 7.1 but ended up not being adopted.


PHP 7.1 : quelques autres nouveautés, en vrac

14 septembre 2016 php, php-7.1

This post is also available in English.
Ceci est le huitième article d’une série à propos de PHP 7.1.


Bien sûr, après un an de travail, les évolutions apportées par PHP 7.1 ne se limitent pas aux points que j’ai présentés ces deniers jours !

Voici donc la suite de cette liste de nouveautés, en regroupant ici la quasi-totalité des améliorations restantes, celles qui ne m’ont pas réellement marqué pour l’instant — mais qui intéresseront peut-être certains d’entre vous ?


Asynchronous Signal Handling

Jusqu’à PHP 7.0, la gestion de signaux par le biais de l’extension pcntl demandait d’appeler pcntl_signal_dispatch() manuellement en synchrone, ou d’utiliser declare(ticks=1) — qui a impact non négligeable sur l’exécution.

Nous utilisons de plus en plus largement PHP en ligne de commandes ou pour des scripts à longue durée de vie, cas où il est intéressant de gérer efficacement les signaux, moyen de communication interprocessus des plus classique. Pour répondre à ce besoin, PHP 7.1 permet désormais de gérer les signaux en asynchrone, à l’aide d’une nouvelle fonction pcntl_async_signals().

pcntl_async_signals(true);

pcntl_signal(SIGTERM, function ($signo) {
    var_dump("SIGTERM"); die;
});

while (true) {
    usleep(100);
}

Un signal TERM envoyé à notre processus (via kill 31321 en adaptant le PID ;-)) déclenchera l’exécution de la fonction anonyme qui affiche ici le nom du signal et met fin à l’exécution du script.

La directive de configuration pcntl.async_signals, à 0 par défaut, permet également d’activer ce fonctionnement de manière systématique, nous évitant alors l’appel à pcntl_async_signals(true). Il est probable que cette valeur par défaut change d’ici une prochaine version de PHP, d’ailleurs.

‣ La RFC : Asynchronous Signal Handling


Octal overflow detection

PHP permet d’inclure un octet dans une chaine de caractères en le représentant en octal :

$str = "Un caractère : \123";
var_dump($str);
// string(17) "Un caractère : S"

Mais, pour réellement tenir sur un octet, le premier digit de la représentation octale doit être compris entre 0 et 3 inclus. Un chiffre plus grand entraine en effet un overflow : "\400" correspond en réalité à "\000", "\500" est interprété comme "\100" et ainsi de suite. Ainsi, la portion de code reproduite ci-dessous donne le même résultat que celle vue plus haut :

$str = "Une tentative : \523";
var_dump($str);
// string(17) "Une tentative : S"

Cet overflow était silencieux jusqu’à PHP 7.0 inclus.
Avec PHP 7.1, le comportement reste identique, mais un avertissement est levé, pour indiquer au développeur qu’il a écrit quelque chose de bizarre :

Warning: Octal escape sequence overflow \523 is greater than \377 in .../demo-01.php on line 12

‣ La RFC : Octal overflow detection


Autres, à voir pour les curieux

Complètement en vrac pour terminer cette liste de nouveautés, voici les autres RFC qui sont passées et qui apportent des évolutions pour PHP 7.1 — sans que je ne présente plus d’exemples ni de reproduise de détail :

Ces évolutions ne devraient pas avoir d’impact majeur sur vos applications, mais peuvent toutefois aider dans certains cas — par exemple, en permettant une représentation plus précise des nombres flottants ou en commençant à introduire un support de HTTP/2.


La fin de cette série approche, mais il me reste encore quelques points à aborder.
Demain, nous verrons une liste d’idées évoquées pendant le cycle de développement de PHP 7.1 mais qui n’ont pas été adoptées.


PHP 7.1: create a Closure from a callable

September 13, 2016 php, php-7.1, english

Cet article est aussi disponible en français.
This is the 7th post in a series about PHP 7.1.


Traditionally, a callable is often handled, in PHP, as a string. For example, we can use the array_map() function, invoking the 'trim' callable on all items of an array.


This approach suffers from a major problem: the callable’s validity is only checked when it’s called!

For example, let’s consider the following portion of code:

function my_function($param)
{
    printf("%s(%s)\n", __FUNCTION__, $param);
}

// No problem is detected here, despite the typo
$nom = 'my_functlon';

// Here, a great number of lines of code
// and many more

// It’s only here we have a problem:
// Warning: call_user_func() expects parameter 1 to be a valid callback, function 'my_functlon' not found or invalid function name
call_user_func($nom, 42);

The typo in the function’s name is not detected when we commit it … but only several lines of code farther, when we try executing it.

In a real case, split over dozens or hundreds of files, maybe also adding a few configuration files in the mix, I’ll let you imagine how hard it could become to debug! Maybe you’ve been in this situation before, actually?


PHP 7.1 solves this problem by adding a new Closure::fromCallable() method. It receives a callable as a parameter, validates it, and returns a Closure referencing it. It is this Closure you will later work with.

We can rewrite the previous example, exploiting this feature. An exception, instance of TypeError, is thrown if the callable you specified is not valid:

function my_function() {
    var_dump(__FUNCTION__);
}

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


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

The nice thing is, if there is a typo in the function’s name (or if it’s not defined because you didn’t include the file where it’s declared), it is immediately detected. You don’t have to wait until you try executing it:

function my_function($param)
{
    printf("%s(%s)\n", __FUNCTION__, $param);
}

// The typo / error is immediately detected
// Fatal error: Uncaught TypeError: Failed to create closure from callable: function 'my_functlon' not found or invalid function name
$callable = Closure::fromCallable('my_functlon');

// Here, a great number of lines of code
// and many more

// No problem here: if there was no error earlier,
// then $callable is always valid
call_user_func($callable, 42);


This same problem, the lack of validation of callables at declaration-time, was also present for other kinds of callables, like those pointing to a method of an object:

class MyClass
{
    protected $data;

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

    public function myMethod()
    {
        printf("%s() -> %s\n", __METHOD__, $this->data);
    }
}


// PHP doesn’t raise any error here, even if it is on this line
// we did a typo!
$callable = [new MyClass(42), 'myMehtod'];


// No error there either!
call_callable($callable);


function call_callable($callable)
{
    // We only get an error here!
    // Fatal error: Uncaught Error: Call to undefined method MyClass::myMehtod()
    $callable();
}

Good news: with PHP 7.1, we can also use Closure::fromCallable() in this case. We also benefit from the validation of the callable when the Closure is created, long before it’s executed:

class MyClass
{
    protected $data;

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

    public function myMethod()
    {
        printf("%s() -> %s\n", __METHOD__, $this->data);
    }
}


// The error is detected right away
// Fatal error: Uncaught TypeError: Failed to create closure from callable: class 'MyClass' does not have a method 'myMehtod'
$callable = Closure::fromCallable([new MyClass(42), 'myMehtod']);


// No problem here: $callable is necessarily valid
call_callable($callable);


// Added bonus: we can use a type-declaration
function call_callable(callable $callable)
{
    $callable();
}

Well, PHP 7.1 brings us a new method, which will help validate callables earlier, in turn facilitating error detection and handling!


‣ The RFC: Closure from callable function