Accueil / Blog / Société / 2017 / Retour sur le PHP Tour 2017

Retour sur le PHP Tour 2017

Par Sébastien Corbin publié 17/07/2017
Contributeurs : Lonny Loquesol
Le PHP Tour se déroulait à Nantes cette année, à deux pas de nos locaux, c'était l'occasion rêvée de sponsoriser et participer à un tel événement.
Retour sur le PHP Tour 2017

En dehors des retrouvailles et rencontres, clin d'œil à Kaliop, JoliCode et Deezer, le PHP Tour est l'occasion d'approfondir ses connaissances et d'en acquérir de nouvelles.

Voici donc un aperçu des conférences qui nous ont particulièrement marquées.

L'état de la SPL dans PHP7

Cette session était donnée par Mark Becker, mainteneur de la suite PHPOffice. Il nous a fait un petit historique de la Standard PHP Library (SPL) qui a été introduite dans la version 5.3.0 du langage.

Les composants les plus connus de la SPL sont en général :

  • l'autoloader (spl_autoload) maintenant abstrait par Composer, et les fonctions qui en dérivent (class_implements, class_uses) ;
  • les classes d'exception (BadFunctionCallException, InvalidArgumentException, RuntimeException, ...) ;
  • l'interface Iterator permettant de boucler sur des collections.

Mais on connaît moins les autres apports de cette SPL comme :

  • les structures de données (SplHeap, SplQueue, SplStack, SplFixedArray, SplDoubleLinkedList, ...) : celles-ci peuvent être appropriées lors de l'implémentation de certains concepts (queue de messages à envoyer, gestion de larges tableaux de données dont la dimension est connue) ;
  • la gestion de fichier avancée (SplFileObject) notamment pour les CSV ;
  • les différents itérateurs déjà disponibles (RecursiveTreeIterator, RecursiveDirectoryIterator, RecursiveFilterIterator, ...) ;
  • la gestion du pattern Observer avec SplObserver.

À partir de ce postulat, la question de pourquoi la SPL n'est pas plus utilisée dans la communauté et le développement quotidien se pose, et c'est souvent par ignorance ou par fainéantise qu'on n'y pense pas.

L'autre raison est aussi celle des performances, à l'heure de PHP 5.3.0, cette SPL avait de vrais avantages comparée à l'utilisation de la reflexivité. Cependant dans PHP 7, ces optimisation de la SPL sont moins marquantes voire ont disparu tant la VM PHP s'est améliorée. Ainsi, les différents frameworks ou bibliothèques continuent d'utiliser leur propres structures (c'est le cas notamment de PHPOffice).

On pourra quand même noter la présence d'une extension PECL php-ds avec polyfill qui s'évertue à implémenter les structures de données de manière efficiente dans PHP 7, sa documentation est d'ailleurs sur php.net.

https://img.youtube.com/vi/So4aCLexnnU/mqdefault.jpg

Dependency Injection & Dependency Inversion

Après avoir vu maintes fois la présentation sur l'injection de dépendance par Fabien Potencier, nous avons assisté à celle de James Mallison qui va plus loin notamment en parlant de l'auto-wiring.

Avec le concept de Dependency Injection Container et de services, il devient logique de vouloir injecter automatiquement les singletons aux constructeurs, c'est le principe de l'auto-wiring. Il permet d'aller plus vite en développement, sous condition d'avoir un peu de magie et du coup d'être moins explicite.

On peut arriver à certaines limites, notamment avec les interfaces, par exemple si j'ai un constructeur public function __construct(FooInterface $foo), je peux automatiquement passer mon singleton si et seulement si un unique objet implémente FooInterface, autrement il faudra établir des paramètres de mapping.

À noter que Symfony propose l'auto-wiring depuis la version 2.8 et au besoin la bibliothèque Auryn répond à ce besoin avec par exemple une intégration au framework Silex.

https://img.youtube.com/vi/qIe6D81kr2g/mqdefault.jpg

API GraphQL

Pour certains le successeur de REST, GraphQL est un query language permettant d'optimiser les échanges réseaux dans des contextes de récupération ou de modification de données auprès d'un backend.

Grâce à cette API, il devient inutile de multiplier les endpoints afin de couvrir l'ensemble des opérations offertes par le backend. C'est désormais au travers du corps de la requête que l'on va déterminer quelles sont les données à récupérer ou à modifier. Un seul endpoint devrait donc suffire dans la majorité des cas.

Le GraphQL arbore une syntaxe proche du JSON auquel on aurait retiré les valeurs. Par exemple :

query getPostList {
  posts {
    title
    author {
      name
      avatar
    }
  }
}

Cette requête peut se traduire par « retourne moi la liste des titres de post associés aux noms et aux avatars des auteurs respectifs ».

Il est bien entendu possible de préciser la requête afin de considérer un unique post, on ajoutera pour cela un « argument » à notre requête :

query getFirstPost {
  posts(id: '1') {
    title
    body
    author {
      name
      avatar
    }
  }
}

Comme vous pouvez le constater dans les exemples ci-dessus, les données demandées sont structurées (les posts référencent leurs auteurs respectifs). Ceci implique qu'un schéma des données ait été défini auprès de l'API afin qu'elle sache comment les manipuler. Pour ce faire une autre syntaxe entre en jeu. Le schéma de données correspondant aux exemples précédents serait le suivant :

type User {
    name: String!
    avatar: String!
}

type Post {
    title: String!
    author: User
}

type Query {
    # Retourne tous les posts si aucun id n'est fourni.
    posts(id: String): [Post]
}

schema {
    # Ici on déclare ce qu'il est possible de demander.
    query: Query
}

L'idée étant ici de donner un petit aperçu du langage nous ne détaillerons pas plus amplement GraphQL. À noter que GraphQL offre également la possibilité de modifier les données, pas seulement de les récupérer. Il se positionne comme un outil de communication entre frontend et backend, ou plus génériquement entre webservices et « consommateurs ».

https://img.youtube.com/vi/xbipW6fgD6c/mqdefault.jpg

Marier ReactJS et Symfony

Présentation très intéressante de Suzanne et Claire de chez Jolicode qui ont décortiqué les différentes méthodes pour intégrer ReactJS à Symfony.

Avec toujours les mêmes points décisifs lorsque l'on parle de Javascript : quid de la SEO, over-engineering, temps de chargement, désactivation du JS...

  • SPA: front React consommant une API REST depuis Symfony

La Single Page App est la solution pour les projets de taille importante, mais elle présente un risque de duplication et nécessite une bonne séparation des rôles (notamment pour la validation de formulaires et la traduction). Comme c'est aussi la plus utilisée, des solutions clé-en-main existent : admin-on-rest, api-platform.

  • Un fichier JS inclus dans Twig

Cette solution hybride est utile lorsque vous avez un site (donc pas une SPA) qui a besoin d'une page très dynamique sans rechargement, par exemple page de recherche de produits.

L'idée est simple, on crée un composant React compilé avec webpack, on passe les données en data-attribute via Twig avec le filtre |json_encode et on inclut le composant compilé avec Assetic.

Le problème se pose pour la SEO et ceux pour qui le JS est désactivé : entre le rendu côté serveur. Celui-ci permet un premier affichage plus rapide et peut être fait grâce à un simple serveur node externe et exec('node ./test.js', $output); et également l'extension PECL V8Js qui execute le JS dans PHP. La bibliothèque PHPExecJS permet de supporter les deux méthodes.

  • En utilisant un bundle de la communauté

Le bundle LimeniusReactBundle se place entre les deux premières solutions et offre une solution facile à intégrer : il compile 2 fichiers JS uniques client-bundle.js et server-bundle.js mais permet d'appeler via Twig chaque composant via la fonction {{ react_component('RecipesApp', {'props': props, 'rendering': 'client_side'}) }} tout en offrant la possibilité de contrôler où se fait le rendu dans la stack.

https://img.youtube.com/vi/ZpIg1AYgBcE/mqdefault.jpg

Object Calisthenics

Vous entendrez sûrement parler de ce terme dans d'autres langages, les Object Calisthenics sont en effet une suite de bonnes pratiques à adopter pour rendre plus lisible votre code POO et aussi éviter les erreurs. Voici la liste succincte :

  • Pas plus d'une seule indentation par méthode Ceci permet de garder un code clair où chaque méthode a une seule responsabilité, de préférence petite
  • Ne pas utiliser le mot-clé "else" Ceci permet de "déplacer" le vrai métier d'une méthode vers sa fin, et de placer au début toutes les sorties simples du style if (!$var) return null;
  • Encapsuler les primitives et les chaînes dans leurs propres classes On pourrait très bien imaginer un montant comme un float (donc primitif), mais lorsque qu'on veut sa valeur HT ou TTC, une classe est la bienvenue, autant la penser dès le début
  • Utiliser des classes de collection Les classes de collection ont une propriété qui représente une liste de valeurs et elles définissent également tout le métier associé à cette liste, qui est donc encapsulé
  • Pas d'abréviation dans le nommage des variables Le nommage est une des deux grosses difficultés en informatique, pourquoi le rendre moins clair en l'abréviant ?
  • Pas de getter ni de setter Les getters sont dangereux, ainsi account.addAmount(PRICE); vaut mieux que account.setAmount(game.getAmount() + PRICE);
  • Pas plus d'un seul point par ligne Dans le cas de PHP, on pourrait plutôt parler de "flèche", le but est d'éviter de chaîner les appels car cela rend le code moins lisible et augment le risque d'appels sur null
  • Pas de classe de plus de 50 lignes Plus c'est long, plus ça a de chance d'être tordu
  • Pas de classe avec plus de deux variables d'instance Cette règle permet d'avoir une meilleure cohésion à travers une meilleure encapsulation, elle va de pair avec l'encapsulation des primitives

Autant les premières sont assez faciles à suivre, autant les dernières peuvent frustrer le développeur et ne sont pas forcément adaptées à toutes les situations.

https://img.youtube.com/vi/aB9pmdtGZjE/mqdefault.jpg

ReactPHP / PHP PM

Ici on ne parlera pas d'un célèbre framework Javascript mais plutôt d'un serveur PHP qui propose d'améliorer significativement le temps de chargement de vos pages.

PHP-PM (pour *process manager*) part d'un simple constat : dans une application PHP, une fois qu'une requête est traitée le thread associée meurt, pourquoi ne pas le faire travailler plusieurs fois d'affilée ? Afin de le garder en vie, il faut donc que le code PHP soit modifié pour bootstraper puis attendre une requête entrante dans une boucle infinie. C'est le rôle de ReactPHP, qui rend non-bloquant l'attente d'une requête entrante. PHP-PM gère l'orchestration des workers, le load balancing, et est compatible avec Symfony, Laravel et Drupal.

Dans la démonstration faite par le speaker, on voyait qu'une application Symfony avait un gain très notable avec un controller renvoyant simplement "hello word". Cependant, la question se pose pour une application plus complexe.

Cette technique, bien que très bien vendue (“PHP 15x plus rapide !“) engendre d'autres problématiques notamment au niveau de la fuite mémoire et de l'introduction d'une incertitude sur l'état du contenu (dans le cas de Symfony).

https://img.youtube.com/vi/VIgCtVUY-FY/mqdefault.jpg

Tagua VM

Cette conférence très intéressante nous faisait un retour d'expérience sur l'écriture d'une VM PHP en Rust. On retiendra qu'il faut beaucoup de patience (30% du langage parsé au bout de 2 ans d'efforts) et de détermination.

Le but est d'amener la robustesse de Rust dans PHP afin de limiter l'introduction de vulnérabilités dans le langage PHP lui-même. L'autre avantage est aussi de créer une VM performante (entendre rapide et peu consommatrice) afin de pousser PHP vers d'autres horizons que le web, comme l'IoT.

https://img.youtube.com/vi/Ymy8qAEe0kQ/mqdefault.jpg

Opcode ? Mais à quoi ça sert ?

Si vous êtes développeur PHP vous avez déjà probablement entendu parler de l'Opcode et avez une idée plus ou moins vague de ce à quoi il sert. C'est en ça qu'il était intéressant d'être présent à cette conférence : découvrir un peu plus précisément de quoi il s'agit.

Pour faire simple, l'Opcode c'est la transformation de votre code PHP en une série d'instructions « simples » bas niveau. L'équivalent de votre code mais sous une forme optimisée pour la VM, plus découpée, plus verbeuse, sans tout le sucre offert par PHP.

L'idée étant de gagner du temps sans avoir à parser l'ensemble des scripts impliqués à chaque exécution, l'Opcode obtenu est alors stocké dans l'Opcache avec une entrée de cache pour chaque script. Tant qu'un script n'a pas été modifié, la VM ira directement chercher sa version optimisée dans le cache. Attention donc à la directive de configuration opcache.max-accelerated-files déterminant le nombre maximal d'entrées possibles dans l'Opcache, sa valeur par défaut (3907) pourrait rapidement devenir insuffisante sachant que tout fichier PHP de votre application devrait être présent dans l'Opcache.

Il était intéressant de constater au travers des exemples du conférencier que certaines petites optimisations auxquelles on peut parfois s'accrocher deviennent en fait absolument inutiles une fois le code retranscrit en Opcode.

Par exemple, si vous vous êtes déjà demandé s'il était plus performant d'utiliser des " ou des ' pour vos chaînes de caractères, ou encore s'il fallait mieux réaliser une concaténation plutôt que de mentionner directement une variable dans une chaîne de caractères, sachez que cela n'a plus aucune importance dans l'Opcode. Quelle que soit la solution choisie, l'Opcode résultant sera le même.

Pour finir sur le sujet, sachez que la totalité du langage PHP s'oriente autour de 180 instructions environ et que l'Opcode était au cœur des dernières améliorations de PHP7 (avec notamment l'apparition du « secondary file-based cache »).

https://img.youtube.com/vi/wiP-gbl-vZA/mqdefault.jpg

PSRs : quoi, pourquoi et comment ?

Les PSRs, tout le monde en a déjà entendu parler. Mais comment naissent-elles ? Qui les écrit ? Comment sont-elles validées ? À quoi servent-elles ?

Voici les questions auxquelles répond Julien Janvier lors de cette conférence en abordant l'histoire du PHP-FIG, son fonctionnement, ainsi que chacune des PSRs déjà existantes.

Qu'est ce que le PHP-FIG ? Un groupe de développeurs, le Framework Interoperability Group, qui en 2009 décide de résoudre le problème de l'interopérabilité au sein de l'environnement PHP. Car oui, à cette époque là, chacun fait un peu à sa façon...

Le FIG se lance alors dans la rédaction des PHP Standard Recommendations. Bien qu'il initie chacune d'elles, les PSRs sont discutées avec la communauté et leurs approbations sont soumises à un vote au sein du groupe.

Elles ont pour objectifs de :

  • rendre le code plus sûr ;
  • améliorer la lisibilité du code à l'aide de "bonnes pratiques" ;
  • augmenter l'interopérabilité au sein de la communauté PHP.

La conférence se conclut d'ailleurs sur ce dernier point qui est le fer de lance du FIG : les PSRs existent pour améliorer la compatibilité entre les divers outils du monde PHP (CMS, frameworks, librairies, etc.) et si rien oblige leur utilisation, il est clairement recommandé de les envisager lorsqu'elles répondent à votre besoin car un certain nombre de personnes se sont déjà penchées sur la question et il est peu probable que vous révolutionniez la solution.

https://img.youtube.com/vi/xkDZF2UM4JQ/mqdefault.jpg

phpSpec : tests unitaires en Behavior Driven Development

Le Behavior Driven Development est une méthode de développement qui permet de décrire les différents comportements des objets, entendre par-là les signatures de leur méthodes.

phpSpec permet ceci, le principe est simple, on écrit une classe qui décrit le comportement qu'aura notre objet, par exemple :

<?php

namespace spec;

use PhpSpec\ObjectBehavior;

class MarkdownSpec extends ObjectBehavior
{
    function it_converts_plain_text_to_html_paragraphs()
    {
        $this->toHtml("Hi, there")->shouldReturn("<p>Hi, there</p>");
    }
}

Puis on lance phpspec avec bin/phpspec run et celui se charge de créer la classe avec ses méthodes telles qu'on l'a décrite. Ainsi, on aura :

<?php

class Markdown
{
    public function toHtml($argument1)
    {
        // TODO: write logic here
    }
}

Il ne nous reste plus qu'à remplir nos méthodes avec notre métier (ici return "<p>Hi, there</p>";), et de ainsi de suite, tel que le prévoit la méthode TDD (Tests Driven Development)

https://img.youtube.com/vi/qh57-OpLiW0/mqdefault.jpg

Les panama papers (Neo4j)

On sort un peu de PHP avec cette conférence rafraîchissante sur l'histoire des Panama Papers, ce scandale qui a éclaté il y a un peu plus d'un an. Cette session est revenue sur les aspects techniques du traitement des 11 millions de documents (soit 2,6To) afin d'enquêter sur les différents acteurs impliqués dans les sociétés offshore basées au Panama.

Tika pour l'OCR, Python pour l'établissement des connexions entre contenus, Solr pour le stockage et l'indexation, et Neo4j pour le stockage en mode graph.

L'intérêt de la base de données en mode graph et de recouper les différentes connexions entre les acteurs et les entreprises. On a ensuite eu droit a quelques requêtes Cypher sur la base Neo4j pour trouver par exemple

  • les intermédiaires les plus sollicités à Paris pour établir les sociétés
  • les paradis fiscaux préférés des français
  • les liens entre 2 entités, quelque soit le chemin
https://img.youtube.com/vi/dsWiQ-ayZTk/mqdefault.jpg

Varnish : comment switcher sa prod sur un Raspberry Pi

Cette conférence nous a rappelé qu'un backend PHP n'est rien sans un reverse proxy tel que Varnish.

Le speaker est revenu sur l'utilisation des tags Varnish avec un exemple de blog codé avec Symfony et admin-on-rest (front React).

Démonstration à l'appui, sur un OrangePi (finalement), le blog est plus de 400 fois plus rapide (en terme de requêtes par seconde) avec Varnish devant. Petite subtilité, il s'avère que le blog aurait pu être encore plus rapide, mais on arrive à une limitation technique qui provient de la carte réseau de l'OrangePi.

https://img.youtube.com/vi/AanufJZXGYs/mqdefault.jpg

Le prochain rendez-vous de l'AFUP

Si vous voulez rencontrer la communauté PHP et discuter de sujets intéressants, le prochain rendez-vous est en octobre 2017 pour le PHP Forum !