Slide 1

Slide 1 text

What’s New ? PHP et Symfony Romain JACQUART & Jérôme TAMARELLE — jeudi 6 juillet 2017

Slide 2

Slide 2 text

Au programme... 1. Piqûre de rappel concernant PHP 5.5 et 5.6 2. Les nouveautés PHP 7.0 et 7.1 3. Les nouveaux composants Symfony 4. Que nous réserve Symfony 4 ?

Slide 3

Slide 3 text

PHP 5.5 Juin 2013

Slide 4

Slide 4 text

5% De gain de performance entre PHP 5.4 et PHP 5.5

Slide 5

Slide 5 text

Générateur — mot clé yield ● Permet d’implémenter un itérateur, sans la complexité d’implémenter l’interface Iterator ● Réduit la mémoire requise lors de la construction d’un jeu de données http://php.net/manual/en/language.generators.overview.php

Slide 6

Slide 6 text

Générateur — mot clé yield Un exemple avec @dataProvider de PHPUnit /** * @dataProvider myData */ public function testSomething($data, $expected) { // ... } public function myData() { yield ['data1', 'expected_data1']; yield ['data2', 'expected_data2']; yield ['data3', 'expected_data3']; } http://php.net/manual/en/language.generators.overview.php

Slide 7

Slide 7 text

Ajout du mot clé finally Dans un try / catch, il est possible d’ajouter un bloc finally, dont le code sera exécuté quel que soit le résultat try { // Code à tester } catch (Exception $e) { // Code en cas d'exception } finally { // Code exécuté dans tous les cas } http://php.net/manual/en/language.exceptions.php

Slide 8

Slide 8 text

Résolution de classe ::class Il est possible de récupérer le FQN (Fully Qualified Name) d’une classe, grâce à ::class namespace Name\Space; class ClassName {} echo ClassName::class; // Name\Space\ClassName" use App\Security\Hasher; $this->prophesize(Hasher::class); http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class

Slide 9

Slide 9 text

list() dans les foreach Il est possible d’utiliser list() directement depuis un foreach, afin d’y extraire des variables distinctes $array = [ [1, 2], [3, 4], ]; foreach ($array as list($a, $b)) { echo "A: $a; B: $b\n"; } // A: 1; B: 2 // A: 3; B: 4 http://php.net/manual/en/control-structures.foreach.php#control-structures.foreach.list

Slide 10

Slide 10 text

Expressions arbitraires dans un empty() empty() supporte désormais tout autre type que des variables function always_empty() { return ''; } if (empty(always_empty())) { // Ce code sera exécuté } http://php.net/manual/en/function.empty.php#refsect1-function.empty-parameters

Slide 11

Slide 11 text

Il est désormais possible de déréférencer directement des array et des string Déréférencement littéral des array et string [1, 2, 3][0] // Retourne 1 'PHP'[0] // Retourne P range(10, 20)[3]; // 13 http://php.net/manual/en/migration55.new-features.php#migration55.new-features.const-dereferencing

Slide 12

Slide 12 text

Nouvelle fonction array_column() $records = [ ['id' => 12, 'name' => 'John'], ['id' => 15, 'name' => 'Sally'], ['id' => 24, 'name' => 'Jane'], ]; $names = array_column($records, 'name'); // ['John', 'Sally', 'Jane'] $names = array_column($records, 'name', 'id'); // [12 => 'John', 15 => 'Sally', 24 => 'Jane'] http://php.net/manual/en/function.array-column.php Retourne les valeurs d’une colonne d’un tableau Le troisième argument permet de garder les clés

Slide 13

Slide 13 text

Nouvelle API de hachage ● password_get_info() — Retourne des informations à propos du hachage fourni ● password_hash() — Crée une clé de hachage pour un mot de passe ● password_needs_rehash() — Vérifie que le hachage fourni est conforme à l'algorithme et aux options spécifiées ● password_verify() — Vérifie qu'un mot de passe correspond à un hachage http://php.net/manual/en/book.password.php

Slide 14

Slide 14 text

PHP 5.6 Août 2014

Slide 15

Slide 15 text

5% De gain de performance entre PHP 5.5 et PHP 5.6

Slide 16

Slide 16 text

Une constante peut maintenant évaluer des expressions scalaires Mais également contenir des tableaux Expressions de constante const UN = 1; // 1 const DEUX = UN * 2; // 2 const TROIS = DEUX + 1; // 3 const TOTAL = 'Total: '.(UN + DEUX + TROIS); // "Total: 6" const NUMBERS = [UN, DEUX, TROIS]; // [1, 2, 3] http://php.net/manual/en/language.constants.syntax.php

Slide 17

Slide 17 text

L’opérateur … peut être utilisé pour créer une fonction variable (variadic function), remplaçant func_get_args() Fonctions variables avec … function fn($req, $opt = null, ...$params) { var_dump($req, $opt, $params); } fn(1); // 1, null, [] fn(1, 2); // 1, 2, [] fn(1, 2, 3); // 1, 2, [3] fn(1, 2, 3, 4); // 1, 2, [3, 4] fn(1, 2, 3, 4, 5); // 1, 2, [3, 4, 5] http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list

Slide 18

Slide 18 text

L’opérateur … (ou splat) peut être utilisé pour décompresser des tableaux et des objets Traversable, dans la liste d’arguments Décompression des arguments avec … function add($a, $b, $c) { return $a + $b + $c; } $operators = [2, 3]; echo add(1, ...$operators); // 6 http://php.net/manual/en/migration56.new-features.php#migration56.new-features.splat

Slide 19

Slide 19 text

Les fonctions array_replace() et array_merge() sont variables Aussi avec array_replace() http://php.net/manual/en/migration56.new-features.php#migration56.new-features.splat $configs = [ ['key1' => 'first array', 'key2' => 0], ['key1' => 'second array'], ]; // Avant PHP 5.6 array_replace($configs[0], $configs[1]); // Après PHP 5.6 array_replace(...$configs); // ['key1' => 'second array', 'key2' => 0]

Slide 20

Slide 20 text

L’opérateur use supporte l’import de fonctions et constantes use const et use function namespace Name\Space { const FOO = 42; function fn() { echo "Hello"; } } namespace { use const Name\Space\FOO; use function Name\Space\fn; echo FOO; // 42 fn(); // Hello } http://php.net/manual/en/language.namespaces.importing.php

Slide 21

Slide 21 text

PHP 7.0 Décembre 2015

Slide 22

Slide 22 text

57% De gain de performance entre PHP 5.6 et PHP 7.0

Slide 23

Slide 23 text

Gestion des erreurs ● La plupart des erreurs fatales ont été remplacées par des levées d’exceptions (ParseError, TypeError…) ● Ces exceptions héritent toutes de la classe Error, qui elle-même implémente l’interface Throwable ● Throwable est la nouvelle interface de base pour tout objet pouvant être lancé par le mot clé throw http://php.net/manual/en/language.errors.php7.php

Slide 24

Slide 24 text

Gestionnaire d’erreur (exception handler) ● Comme pour toutes exceptions, ces Error vont remonter jusqu’au premier bloc catch ● Si aucun bloc catch n’a été trouvé, le gestionnaire d’erreur défini par set_exception_handler() sera appelé ● Si aucun gestionnaire d’erreur n’a été défini et qu’il n’y a pas de gestionnaire par défaut, alors une erreur fatale — à l’ancienne – sera lancée http://php.net/manual/en/language.errors.php7.php

Slide 25

Slide 25 text

Un gestionnaire d’erreur n’est plus certain de recevoir uniquement des objets Exception Gestionnaire d’erreur Exception vs Error // Ne fonctionne qu’en PHP 5 function handler(Exception $e) { ... } set_exception_handler('handler'); // Compatible PHP 5 et 7 function handler($e) { ... } // Ne fonctionne qu’en PHP 7 function handler(Throwable $e) { ... } http://php.net/manual/en/function.set-exception-handler.php

Slide 26

Slide 26 text

4 types scalaires ont été ajoutés, afin d’enrichir le typage actuel : string, int, float et bool Typage scalaire des paramètres function fn(string $a, int $b, float $c, bool $d) { var_dump($a, $b, $c, $d); } fn('Hello', 4, 2.5, true); // string(5) "Hello" // int(4) // float(2.5) // bool(true) fn('Hello', 'World', 2.5, true); // Fatal error: Uncaught TypeError: Argument 2 passed // to fn() must be of the type integer, string given http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration

Slide 27

Slide 27 text

Il est possible de typer la valeur de retour d’une fonction Ce typage implique un transtypage de la valeur retournée Déclaration des types de retour function greet(string $name): string { return "Hello $name!"; } var_dump(greet('World')); // string(12) "Hello World!" function sum($a, $b): float { return $a + $b; } var_dump(sum(1, 2)); // float(3) http://php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration

Slide 28

Slide 28 text

Retourne la première valeur, depuis la gauche vers la droite, qui existe et différente de NULL Opérateur d’union nul (null coalescing) $username = $_GET['user'] ?? 'anonymous'; // Est l'équivalent de : $username = isset($_GET['user']) ? $_GET['user'] : 'anonymous'; // Il peut être chaîné : $username = $_GET['user'] ?? $_POST['user'] ?? 'anonymous'; http://php.net/manual/en/language.operators.comparison.php

Slide 29

Slide 29 text

Retourne -1, 0 ou 1 lorsque $a est respectivement inférieur, égal ou supérieur à $b Opérateur combiné (spaceship operator) // Entiers echo 1 <=> 2; // -1 echo 1 <=> 1; // 0 echo 2 <=> 1; // 1 // Strings echo 'a' <=> 'b'; // -1 echo 'a' <=> 'a'; // 0 echo 'b' <=> 'a'; // 1 // Tableaux echo [1, 2] <=> [1, 3]; // -1 echo [1, 2] <=> [1, 2]; // 0 echo [1, 2] <=> [1, 1]; // 1 http://php.net/manual/en/language.operators.comparison.php

Slide 30

Slide 30 text

Il est possible de définir une constante dont la valeur est un tableau Définition de constante avec un tableau define('ANIMALS', [ 'dog', 'cat', 'bird', ]); echo ANIMALS[1]; // "cat" http://php.net/manual/en/language.constants.syntax.php

Slide 31

Slide 31 text

list() assigne désormais les variables dans le sens normal de définition, contrairement au sens inverse Changements concernant list() list($a[], $a[], $a[]) = [1, 2, 3]; var_dump($a); // PHP 5: [3, 2, 1] // PHP 7: [1, 2, 3] http://php.net/manual/en/function.list.php

Slide 32

Slide 32 text

Il n’est plus possible d’utiliser un list() vide Changements concernant list() $a = [1, 2, 3]; list() = $a; list(,,) = $a; list($x, list(), $y) = $a; // Fatal error: Cannot use empty list http://php.net/manual/en/function.list.php

Slide 33

Slide 33 text

Les classes, fonctions et constantes d’un même namespace peuvent être groupées lors de l’import Déclarations groupées avec use // Avant PHP 7 use Name\Space\ClassA; use Name\Space\ClassB as B; use function Name\Space\fnA; use function Name\Space\fnB; use const Name\Space\CONST_A; use const Name\Space\CONST_B; // Après PHP 7 use Name\Space\{ClassA, ClassB as B}; use function Name\Space\{fnA, fnB}; use const Name\Space\{CONST_A, CONST_B}; http://php.net/manual/en/language.namespaces.importing.php#language.namespaces.importing.group

Slide 34

Slide 34 text

Il est possible de créer des classes anonymes grâce à new class, lorsque de simples objets uniques ont besoin d’être créés Classes anonymes $logger = new class { public function log($msg) { echo $msg; } }; var_dump($logger); // object(class@anonymous)#1 (0) {} $logger->log('Hello world'); // Hello world http://php.net/manual/en/language.oop5.anonymous.php

Slide 35

Slide 35 text

Celles-ci peuvent étendre et implémenter d’autres classes Classes anonymes use Psr\Log\AbstractLogger; $logger = new class extends AbstractLogger { public function log($level, $message, array $context = []) { echo "[$level] $message"; } }; $logger->info('Hello World!'); // [info] Hello World! http://php.net/manual/en/language.oop5.anonymous.php

Slide 36

Slide 36 text

Un return final peut être récupéré avec Generator::getReturn() mais uniquement après avoir passé tous les yield du générateur return final d’un générateur $generator = (function () { yield 1; yield 2; return 'The end!'; })(); foreach ($generator as $value) { echo "$value "; } // 1 2 echo $generator->getReturn(); // "The end!" http://php.net/manual/en/generator.getreturn.php

Slide 37

Slide 37 text

Permet d’obtenir les valeurs d’un autre générateur, d’un objet Traversable ou d’un tableau Délégation du générateur avec yield from function count_to_ten() { yield 1; yield from new ArrayIterator([2, 3, 4]); yield from five_to_ten(); } function five_to_ten() { yield from [5, 6, 7, 8, 9, 10]; } foreach (count_to_ten() as $num) { echo "$num "; } // 1 2 3 4 5 6 7 8 9 10 http://php.net/manual/en/language.generators.syntax.php#control-structures.yield.from

Slide 38

Slide 38 text

Adieu mysql_query() Les extensions mysql et mssql ont été retirées Il n’est donc plus possible d’utiliser les fonctions associées, comme : mysql_connect(), mysql_query(), mysql_fetch_array()... Alternatives : PDO ou mysqli http://php.net/manual/en/ref.mysql.php - http://php.net/manual/en/ref.mssql.php

Slide 39

Slide 39 text

Adieu ereg_replace() Le support des expressions rationnelles avancées de POSIX a été supprimé Il n’est donc plus possible d’utiliser les fonctions associées, comme : ereg(), ereg_replace(), split()... Alternative : les expressions rationnelles Perl (PCRE) http://php.net/manual/en/ref.regex.php

Slide 40

Slide 40 text

PHP 7.1 Décembre 2016

Slide 41

Slide 41 text

30% De gain de performance entre PHP 7.0 et PHP 7.1

Slide 42

Slide 42 text

Le type des paramètres d’une fonction peut être marqué comme nullable en le préfixant de ? Ajout du nullable avec ? function fn(?string $name) { var_dump($name); } fn('Hello'); // string(5) "Hello" fn(null); // NULL fn(); // Fatal error: Uncaught ArgumentCountError: // Too few arguments to function fn() http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration

Slide 43

Slide 43 text

Et également sur le type de retour d’une fonction Ajout du nullable avec ? function fn(?string $name): ?string { return $name; } var_dump(fn('Hello')); // string(5) "Hello" var_dump(fn(null)); // NULL http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration

Slide 44

Slide 44 text

Les fonctions de type void ne doivent rien retourner Ajout du type de retour void function no_return(): void { // valide } function empty_return(): void { return; // valide } function returns_one(): void { return 1; // Fatal error: A void function must not return a value } function returns_null(): void { return null; // Fatal error: A void function must not return a value } https://wiki.php.net/rfc/void_return_type

Slide 45

Slide 45 text

La notation courte des tableaux peut être utilisée en remplacement du list() Déstructuration symétrique de tableau $data = [ [12, 'John'], [15, 'Doe'], ]; [$id, $name] = $data[0]; // Identique à : list($id, $name) = $data[0]; // Ou dans un foreach foreach ($data as [$id, $name]) { var_dump($id, $name); } https://wiki.php.net/rfc/short_list_syntax

Slide 46

Slide 46 text

La visibilité d’une constante de classe est maintenant supportée Visibilité des constantes de classe class Demo { public const CONST_A = 1; protected const CONST_B = 2; private const CONST_C = 3; } var_dump(Demo::CONST_A); // int(1) var_dump(Demo::CONST_B); // Fatal error: Uncaught Error: Cannot access protected const var_dump(Demo::CONST_C); // Fatal error: Uncaught Error: Cannot access private const http://php.net/manual/en/language.oop5.constants.php

Slide 47

Slide 47 text

A l’image du pseudo-type callable, celui-ci n’accepte que des tableaux ou objets Traversable Pseudo-type iterable function foo(iterable $iterable) { foreach ($iterable as $value) { // ... } } function bar(): iterable { return [1, 2, 3]; } function generator(): iterable { yield 1; yield 2; } http://php.net/manual/en/language.types.iterable.php

Slide 48

Slide 48 text

Il est possible d’attraper plusieurs exceptions, dans un même bloc catch avec | Multi catch d’Exception try { // Code à tester } catch (FirstException | SecondException $e) { // Code traitant l'exception } http://php.net/manual/en/language.exceptions.php#language.exceptions.catch

Slide 49

Slide 49 text

Des clés peuvent être spécifiées dans un list() afin de faciliter le mapping Support des clés dans un list() $data = [ ['id' => 1, 'name' => 'Tom'], ['id' => 2, 'name' => 'Fred'], ]; // list() style list('id' => $id, 'name' => $nickname) = $data[0]; // [] style ['id' => $id, 'name' => $nickname] = $data[0]; // foreach [] style foreach ($data as ['id' => $id, 'name' => $nickname]) { // Code traitant $id et $nickname } http://php.net/manual/en/function.list.php

Slide 50

Slide 50 text

Possible de fournir un offset négatif lors d’une manipulation de string Offset de string négatif $string = 'bar'; echo "Le dernier caractère de '$string' est '$string[-1]'."; // "Le dernier caractère de 'bar' est 'r'." http://php.net/manual/en/language.types.string.php#language.types.string.substr

Slide 51

Slide 51 text

Une exception est levée, plutôt qu’un warning, lors d’un appel à une fonction personnalisée où il manque des arguments Exception lors d’un manque d’argument function fn($param) { var_dump($param); } fn(); // Avant PHP 7.1 : // Warning: Missing argument 1 for fn() // Après PHP 7.1 : // Fatal Error: Uncaught ArgumentCountError: // Too few arguments to function fn() http://php.net/manual/en/migration71.incompatible.php#migration71.incompatible.too-few-arguments-exception

Slide 52

Slide 52 text

La construction d’un DateTime sur l’heure courante prend en compte les microsecondes DateTime gère les microsecondes var_dump(new DateTime() == new DateTime()); // Avant PHP 7.1 : bool(true) // Après PHP 7.1 : bool(false) http://php.net/manual/en/migration71.incompatible.php#migration71.incompatible.datetime-microseconds

Slide 53

Slide 53 text

Performances

Slide 54

Slide 54 text

Performances Résultat immédiat d’une montée de version https://twitter.com/acasademont/status/710444965596426241

Slide 55

Slide 55 text

Performances Résultat immédiat d’une montée de version https://www.cloudways.com/blog/php-5-6-vs-php-7-symfony-benchmarks/

Slide 56

Slide 56 text

PHPUnit

Slide 57

Slide 57 text

Utilisation des namespace avec PSR-4 Toutes les classes du coeur de PHPUnit 6.0 ont été renommées pour utiliser les namespaces // Avant PHPUnit 6.0 class SerialiserTest extends \PHPUnit_Framework_TestCase { public function testSerialize() {} } // Depuis PHPUnit 6.0 use PHPUnit\Framework\TestCase; class SerialiserTest extends TestCase { public function testSerialize() {} } https://thephp.cc/news/2017/02/migrating-to-phpunit-6

Slide 58

Slide 58 text

Symfony Assets

Slide 59

Slide 59 text

JSON Manifest — Symfony 3.3 http://symfony.com/blog/new-in-symfony-3-3-manifest-based-asset-versioning / webpack-manifest-plugin # app/config/config.yml framework: assets: json_manifest_path: '%kernel.root_dir%/../web/build/manifest.json' { "css/app.css": "build/css/app.b91642.css", "images/logo.png": "build/images/logo.136309.png" }

Slide 60

Slide 60 text

WebLink Component ● Transmet au navigateur des liens de ressources à pré-charger, en passant des headers HTTP Link ● Utile pour le “Server Push” HTTP/2 ● Intègre les helpers Twig link(), preload(), dns_prefetch(), preconnect(), prefetch(), prerender() http://symfony.com/blog/new-in-symfony-3-3-weblink-component

Slide 61

Slide 61 text

Webpack Encore — Abandon de Assetic ● Assetic c’est totalement dépassé ● Objectif : faciliter la prise en main de webpack https://www.npmjs.com/package/@symfony/webpack-encore Symfony ne seraient-ils pas en train de se disperser ? https://symfony.com/blog/introducing-webpack-encore-for-asset-management

Slide 62

Slide 62 text

Symfony Dependency Injection

Slide 63

Slide 63 text

Autowire Définir un service sans déclarer explicitement les dépendances namespace AppBundle\Service; class TwitterClient { function __construct(HttpClient $client) {} function setLogger(LoggerInterface $log) {} } https://symfony.com/doc/current/service_container/autowiring.html services: _defaults: autowire: true autoconfigure: true public: false AppBundle\Service\TwitterClient: public: true

Slide 64

Slide 64 text

Chargement automatique Détection automatique des nouvelles classes et enregistrement des services http://symfony.com/doc/master/service_container/3.3-di-changes.html # app/config/services.yml services: App\Service\: resource: 'src/AppBundle/Service' App\Controller\: resource: 'src/AppBundle/Controller' public: true tags: ['controller.service_arguments']

Slide 65

Slide 65 text

Symfony Components

Slide 66

Slide 66 text

Cache — Symfony 3.1 Implémente PSR-16 Complète Doctrine\Cache ● Invalidation par tags ● Expiration Intégré au framework $cache = new TagAwareAdapter( // Adapter for cached items new FilesystemAdapter(), // Adapter for tags new RedisAdapter('redis://localhost') ); $item = $cache->getItem('cache_key'); $item->tag(['tag_2', 'tag_3']); $cache->save($item); $cache->invalidateTags(['tag_1', 'tag_3']); http://symfony.com/doc/current/components/cache.html — https://symfony.com/blog/new-in-symfony-3-1-cache-component

Slide 67

Slide 67 text

Workflow — Symfony 3.2 Flux de travail Article Démo : Flux de travail d’un article (sources) https://symfony.com/doc/current/components/workflow.html

Slide 68

Slide 68 text

WebServerBundle — Symfony 3.3 Extrait du FrameworkBundle : activé uniquement en dev. http://symfony.com/blog/new-in-symfony-3-3-webserverbundle

Slide 69

Slide 69 text

Dotenv — Symfony 3.3 Défini des valeurs par défaut pour les variables d’environnement parameters.yml remplacé par le fichier .env # .env DEBUG=true DATABASE_URL=mysql://[email protected]:3306/symfony https://symfony.com/doc/current/components/dotenv.html # config.yml doctrine: dbal: url: '%env(DATABASE_URL)%'

Slide 70

Slide 70 text

Lock — Symfony 3.4 Verrouille l’accès à une ressource pendant un temps déterminé pour éviter les traitements parallèles $store = new MemcachedStore($memcached, $ttl) $factory = new Factory($store); $lock = $factory->createLock('pdf-generation'); if ($lock->acquire()) { // The resource "pdf-generation" is locked. $lock->release(); } http://symfony.com/blog/new-in-symfony-3-3-lock-component

Slide 71

Slide 71 text

Symfony 4

Slide 72

Slide 72 text

Variables d’environnement ● Recommandation du 12 factor Application Manifesto ● Plus standard que le fichier parameters.yml ● bin/console --env=prod devient SYMFONY_ENV=prod bin/console ● 1 seul fichier de contrôleur public/index.php configuré par nginx

Slide 73

Slide 73 text

Nouvelle structure de répertoires Nouveauté Symfony 3.4 : %kernel.project_dir% donne la racine du projet Conception bundle-less .env (remplace parameters.yml) config/ packages/ doctrine.yaml bundles.php routing.yaml public/ (remplace web) index.php src/ Controllers/ Kernel.php templates/ (remplace views) base.html.twig tests/ var/ (cache, logs) Makefile http://fabien.potencier.org/symfony4-directory-structure.html

Slide 74

Slide 74 text

Symfony Flex ● Skeleton épuré : juste un composer.json ● Plugin composer pour configurer les packages installés en utilisant des recipes officielles ou contribuées par la communauté ● Impose des conventions

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

Merci pour votre écoute