Share
Embed
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
Transcript
76 slides
-
What’s New ? PHP et Symfony Romain JACQUART & Jérôme
TAMARELLE — jeudi 6 juillet 2017 -
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 ? -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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] -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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') }}" /> -
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 -
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 -
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 -
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'] -
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 -
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 -
WebServerBundle — Symfony 3.3 Extrait du FrameworkBundle : activé uniquement
en dev. http://symfony.com/blog/new-in-symfony-3-3-webserverbundle -
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)%' -
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 -
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 -
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 -
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