lundi 26 septembre 2016

PHP a 2 types de tableaux

Derrière ce titre racoleur se cache une vérité : PHP gère bien 2 types de tableaux. Une version "standard", avec des clefs numériques, et une version "associative", avec des clefs type string.
Documentation PHP sur array

Comment PHP passe d'un tableau standard à un tableau associatif, sans nous le dire, et sans qu'on puisse le voir même avec un var_dump() ?
Si on ajoute des valeurs dans un tableau qui n'a que des clefs numériques, qui partent de 0, et qui n'ont pas de trou, alors c'est un tableau standard.
Du moment qu'un tableau a des trous dans ses clefs numériques, ou qu'on ajoute une clef type string, alors c'est un tableau associatif.

Un auto-cast en int des clefs est effectué en interne. Ce qui veut dire qu'une clef '0' sera automatiquement transformée en intval('0'), et notre tableau final n'aura pas une clef type string mais bien type int.
Cet auto-cast supprime également les parties décimales des float. Par exemple, une clef 0.5 sera transformée en 0, alors qu'une clef '0.5' restera bien telle quelle.

Quelques exemples pour illustrer cette explication :
// tableau standard $array = [ 'foo', 'bar' ]; // type de tableau non modifié, c'est encore un tableau standard $array[] = 'baz'; // typage transparent en tableau associatif $array[10] = 'tou'; // tableau standard, même si on met une chaine en clef // comme c'est '0', c'est casté en int en interne. la clef '0' devient 0. $array2 = [ '0' => 'foo' ]; // tableau associatif, on n'a pas de clef pour 2 $array3 = [ 0 => 'foo', 1 => 'bar', 3 => 'baz' ]; // tableau standard, l'auto-cast des clefs transforme 1.5 en 1 $array4 = [ 0 => 'foo', 1.5 => 'bar' ]; // tableau associatif, la clef '1.5' conserve son type string $array5 = [ 0 => 'foo', '1.5' => 'bar' ];

La réaction de json_encode() aux 2 types de tableaux


Pour se rendre compte de tout ça, un appel à json_encode($array) peut-être effectué avec les cas de test ci-dessus :
  • Quand le retour est un tableau, c'est un tableau standard
  • Quand le retour est un objet, c'est un tableau associatif
Cette différence est très importante.
Par exemple, pour les cas $array3 et $array5, si on fait un bête json_decode(json_encode($array3)), on n'obtient pas un array, mais un \stdClass !

lundi 19 septembre 2016

Issue #6042 : lazy loading inutile si on définit getId() dans un trait

Lorsqu'on veut accéder à un identifiant d'une entité qui n'est pas encore chargée par Doctrine, et qu'on passe donc par un proxy, aucun lazy loading n'est effectué parceque le Proxy contient déjà l'identifiant. N'importe quel accès à une autre propriété effectuera un lazy loading.

Si on définit la méthode getId() d'une entité dans un trait, lors de l'appel à getId(), un lazy loading sera effectué. Le Proxy généré ne comprend pas que la méthode getId() n'accède qu'à l'identifiant, et a le même comportement que n'importe quelle autre accesseur.

Issue #6042

lundi 5 septembre 2016

Issue #19860 : les constructeurs des Listeners ne sont pas appelés suivant la priorité des services

Dans le fichier var/cache/classes.php, généré par Symfony, une méthode protected function lazyLoad($eventName) est créée.

Cette méthode appelle tous les constructeur de tous les listeners d'un même événement, avant même que la méthode liée à l'événement (onKernelRequest par exemple) du listener ayant la priorité la plus haute soit appelée.
Ces constructeurs ne sont pas appelés selon la priorité des services, mais selon l'ordre d'enregistrement dans le Container.
De plus, comme tous les constructeurs sont appelés avant les méthodes liées à l'événement, on ne peut pas avoir un listener A qui créé / modifie une donnée dont aura besoin le listener B dans son constructeur.

Issue #19860