Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Quoi de neuf sur Symfony et PHP ? - Prisma Media

Quoi de neuf sur Symfony et PHP ? - Prisma Media

Revue des nouveautés de PHP 5.5 à 7.2
Nouveaux composants Symfony, introduction à Symfony Flex
Présentation destinée aux développeurs Prisma Media.

Jérôme Tamarelle

July 06, 2017
Tweet

More Decks by Jérôme Tamarelle

Other Decks in Programming

Transcript

  1. 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 ?
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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]
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. 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
  42. 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
  43. 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
  44. 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
  45. 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" } <link href="{{ asset('/css/app.css') }}"> <img src="{{ asset('images/logo.png') }}" />
  46. 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
  47. 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
  48. 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
  49. 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']
  50. 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
  51. 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
  52. WebServerBundle — Symfony 3.3 Extrait du FrameworkBundle : activé uniquement

    en dev. http://symfony.com/blog/new-in-symfony-3-3-webserverbundle
  53. 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)%'
  54. 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
  55. 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
  56. 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
  57. 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