Nous avons certainement tous appris les structures de données à l'école: tableaux, listes, ensembles, piles, files (LIFO/FIFO), tas, tableaux associatifs, arbres,... et qu'utilisons-nous principalement en PHP? Les tableaux! Comme si ils avaient réponse à tout! Inévitablement, on retombe sur ce genre de problèmes fondamentaux lors d'audits de performance. Dans cette session, on apprendra quelques techniques avancées en réapprenant à se servir des types de données adéquats, en passant par des utilisations spécifiques des "arrays" PHP, des classes de la SPL ainsi que d'autres structures fournies par des extensions PHP/PECL.
18. Array: Le mensonge PHP
Les “Arrays” PHP ne sont pas de vrais tableaux!
Un tableau ressemble typiquement à:
0 1 2 3 4 5
Data Data Data Data Data Data
19. Array: Le mensonge PHP
Les “Arrays” PHP peuvent être modifiés dynamiquement et
être itérés dans différentes directions (reset(), next(), prev(),
end()), et ce exclusivement avec des operations en O(1).
20. Array: Le mensonge PHP
Les “Arrays” PHP peuvent être modifiés dynamiquement et
être itérés dans différentes directions (reset(), next(), prev(),
end()), et ce exclusivement avec des operations en O(1).
Imaginons une liste doublement chainée:
Head Tail
Data Data Data Data Data
Permet d'implémenter: Liste, Deque, File et Tas
21. Array: Le mensonge PHP
Les éléments d'un“Array” PHP peuvent à tout
moment être accédés au moyen d'une clé (index).
22. Array: Le mensonge PHP
Les éléments d'un“Array” PHP peuvent à tout
moment être accédés au moyen d'une clé (index).
Voyons avec une table de hachage:
Head Bucket pointers array Tail
0 1 2 3 4 5 ... nTableSize -1
Bucket * Bucket * Bucket * Bucket * Bucket * Bucket * Bucket *
Bucket Bucket Bucket Bucket Bucket
Data Data Data Data Data
23. Array: Le mensonge PHP
http://php.net/manual/fr/language.types.array.php:
“Ce type est optimisé pour différentes
utilisations ; il peut être considéré comme
un tableau, une liste, une table de
hashage, un dictionnaire, une collection,
une pile, une file d'attente et
probablement plus.”
25. Array: Le mensonge PHP
● En C: 100 000 entiers (long sur 64bits => 8 octets)
peuvent être stockés moyennant 0.76 Mo.
● En PHP: cela prend ≅ 13.97 Mo!
● Une variable PHP (contenant un entier par
exemple) prend 48 octets.
● L'overhead des buckets pour chacune des entrées
d'un “array” est approximativement: 96 octets.
● Plus de détails:
http://nikic.github.com/2011/12/12/How-big-are-PHP-arrays-really-Hint-BIG.html
28. Structs (ou records, tuples,...)
● Une struct est une valeur contenant
habituellement plusieurs autres valeurs et qui sont
accédées moyennant un nom.
● Exemple:
Person => firstName / lastName
ComplexNumber => realPart / imaginaryPart
29. Structs – Avec un array
$person = array(
"firstName" => "Patrick",
"lastName" => "Allaert"
);
30. Structs – Avec une classe
$person = new PersonStruct(
"Patrick", "Allaert"
);
31. Structs – Avec une classe
(Implémentation)
class PersonStruct
{
public $firstName;
public $lastName;
public function __construct($firstName, $lastName)
{
$this->firstName = $firstName;
$this->lastName = $lastName;
}
}
32. Structs – Avec une classe
(Implémentation)
class PersonStruct
{
public $firstName;
public $lastName;
public function __construct($firstName, $lastName)
{
$this->firstName = $firstName;
$this->lastName = $lastName;
}
public function __set($key, $value)
{
// a. Ne rien faire
// b. trigger_error()
// c. Lancer une exception
}
}
33. Structs – Avantages et
inconvénients
Array Class
+ Utilise moins de mémoire - Utilise plus de mémoire (PHP <
(PHP < 5.4) 5.4)
- Utilise plus de mémoire (PHP = + Utilise moins de mémoire
5.4) (PHP = 5.4)
- Pas de type hinting + Type hinting possible
- Structure flexible + Structure rigide
+|- Moins OO +|- Plus OO
35. (vrai) Tableaux
● Un tableau est une collection de taille fixe dont les
éléments sont tous identifiés par un index
numérique.
36. (vrai) Tableaux
● Un tableau est une collection de taille fixe dont les
éléments sont tous identifiés par un index
numérique.
0 1 2 3 4 5
Data Data Data Data Data Data
37. (vrai) Tableaux – Avec
SplFixedArray
$array = new SplFixedArray(3);
$array[0] = 1; // ou $array->offsetSet()
$array[1] = 2; // ou $array->offsetSet()
$array[2] = 3; // ou $array->offsetSet()
$array[0]; // donne 1
$array[1]; // donne 2
$array[2]; // donne 3
38. (vrai) Tableaux – Avantages et
inconvénients
Array SplFixedArray
- Utilise plus de mémoire + Utilise moins de mémoire
+|- Moins OO +|- Plus OO
40. Files
● Une pile est une collection ordonnée respectant
l'ordre First In, First Out (FIFO).
● Les éléments sont insérés d'un côté et enlevés de
l'autre.
41. Files
● Une pile est une collection ordonnée respectant
l'ordre First In, First Out (FIFO).
● Les éléments sont insérés d'un côté et enlevés de
l'autre.
Data
Dequeue
Data Data Data Data Data Data
Enqueue
Data
42. Files – Avec un array
$queue = array();
$queue[] = 1; // ou array_push()
$queue[] = 2; // ou array_push()
$queue[] = 3; // ou array_push()
array_shift($queue); // donne 1
array_shift($queue); // donne 2
array_shift($queue); // donne 3
43. Files – Avec SplQueue
$queue = new SplQueue();
$queue[] = 1; // ou $queue->enqueue()
$queue[] = 2; // ou $queue->enqueue()
$queue[] = 3; // ou $queue->enqueue()
$queue->dequeue(); // donne 1
$queue->dequeue(); // donne 2
$queue->dequeue(); // donne 3
45. Piles
● Une pile est une collection ordonnée respectant
l'ordre Last In, First Out (LIFO).
● Les éléments sont insérés et enlevés du même
côté.
46. Piles
● Une pile est une collection ordonnée respectant
l'ordre Last In, First Out (LIFO).
● Les éléments sont insérés et enlevés du même
côté.
Data
Push
Data Data Data Data Data Data
Pop
Data
47. Piles – Avec un array
$stack = array();
$stack[] = 1; // ou array_push()
$stack[] = 2; // ou array_push()
$stack[] = 3; // ou array_push()
array_pop($stack); // donne 3
array_pop($stack); // donne 2
array_pop($stack); // donne 1
48. Piles – Avec SplStack
$stack = new SplStack();
$stack[] = 1; // ou $stack->push()
$stack[] = 2; // ou $stack->push()
$stack[] = 3; // ou $stack->push()
$stack->pop(); // donne 3
$stack->pop(); // donne 2
$stack->pop(); // donne 1
49. Files/Piles – Avantages et
inconvénients
Array SplQueue / SplStack
- Utilise plus de mémoire + Utilise moins de mémoire
(overhead / entrée: 96 octets) (overhead / entrée: 48 octets)
- Pas de type hinting + Type hinting possible
+|- Moins OO +|- Plus OO
50. Ensembles
Geeks Nerds
Personnes ayant
une opinion très
tranchée sur la
différence
entre geeks et
nerds
51. Ensembles
● Un ensemble est une collection sans ordre
spécifique particulièrement adapté pour tester
l'appartenance d'une valeur à une collection ou
pour réaliser une opération
d'union/d'intersection/de complément entre eux.
52. Ensembles
● Un ensemble est une collection sans ordre
spécifique particulièrement adapté pour tester
l'appartenance d'une valeur à une collection ou
pour réaliser une opération
d'union/d'intersection/de complément entre eux.
Data
Data
Data
Data
Data
53. Ensembles – Avec un array
$set = array();
// Adding elements to a set
$set[] = 1;
$set[] = 2;
$set[] = 3;
// Checking presence in a set
in_array(2, $set); // true
in_array(5, $set); // false
array_merge($set1, $set2); // union
array_intersect($set1, $set2); // intersection
array_diff($set1, $set2); // complement
54. Ensembles – Avec un array
$set = array();
// Adding elements to a set
$set[] = 1;
$set[] = 2;
$set[] = 3; True
// Checking presence in a set performance
in_array(2, $set); // true
in_array(5, $set); // false
killers!
array_merge($set1, $set2); // union
array_intersect($set1, $set2); // intersection
array_diff($set1, $set2); // complement
58. Ensembles – Avec un array (types
simples)
$set = array();
// Adding elements to a set
$set[1] = true; // Any dummy value
$set[2] = true; // is good but NULL!
$set[3] = true;
// Checking presence in a set
isset($set[2]); // true
isset($set[5]); // false
$set1 + $set2; // union
array_intersect_key($set1, $set2); // intersection
array_diff_key($set1, $set2); // complement
59. Ensembles – Avec un array (types
simples)
$set = array();
// Adding elements to a set
$set[1] = true; // Any dummy value
$set[2] = true; // is good but NULL!
$set[3] = true;
// Checking presence in a set
isset($set[2]); // true
isset($set[5]); // false
$set1 + $set2; // union
array_intersect_key($set1, $set2); // intersection
array_diff_key($set1, $set2); // complement
● Attention : les clés d'un array PHP ne peuvent être
que des entiers ou des strings !
60. Ensembles – Avec un array (objets)
$set = array();
// Adding elements to a set
$set[spl_object_hash($object1)] = $object1;
$set[spl_object_hash($object2)] = $object2;
$set[spl_object_hash($object3)] = $object3;
// Checking presence in a set
isset($set[spl_object_hash($object2)]); // true
isset($set[spl_object_hash($object5)]); // false
$set1 + $set2; // union
array_intersect_key($set1, $set2); // intersection
array_diff_key($set1, $set2); // complement
61. Ensembles – Avec un array (objets)
$set = array();
// Adding elements to a set
$set[spl_object_hash($object1)] = $object1; Store a
$set[spl_object_hash($object2)] = $object2; reference of
$set[spl_object_hash($object3)] = $object3; the object!
// Checking presence in a set
isset($set[spl_object_hash($object2)]); // true
isset($set[spl_object_hash($object5)]); // false
$set1 + $set2; // union
array_intersect_key($set1, $set2); // intersection
array_diff_key($set1, $set2); // complement
62. Ensembles – Avec
SplObjectStorage (objets)
$set = new SplObjectStorage();
// Adding elements to a set
$set->attach($object1); // ou $set[$object1] = null;
$set->attach($object2); // ou $set[$object2] = null;
$set->attach($object3); // ou $set[$object3] = null;
// Checking presence in a set
isset($set[$object2]); // true
isset($set[$object2]); // false
$set1->addAll($set2); // union
$set1->removeAllExcept($set2); // intersection
$set1->removeAll($set2); // complement
63. Ensembles – Avec QuickHash (int)
$set = new QuickHashIntSet(64,
QuickHashIntSet::CHECK_FOR_DUPES);
// Adding elements to a set
$set->add(1);
$set->add(2);
$set->add(3);
// Checking presence in a set
$set->exists(2); // true
$set->exists(5); // false
// Soonish: isset($set[2]);
● Pas (encore?) d'opérations d'union/d'intersection/de
complément.
● Fonctionnalités intéressantes : (loadFrom|saveTo)(String|File)
64. Ensembles – Avec des bitsets
define("E_ERROR", 1); // ou 1<<0
define("E_WARNING", 2); // ou 1<<1
define("E_PARSE", 4); // ou 1<<2
define("E_NOTICE", 8); // ou 1<<3
// Adding elements to a set
$set = 0;
$set |= E_ERROR;
$set |= E_WARNING;
$set |= E_PARSE;
// Checking presence in a set
$set & E_ERROR; // true
$set & E_NOTICE; // false
$set1 | $set2; // union
$set1 & $set2; // intersection
$set1 ^ $set2; // complement
65. Ensembles – Avec des bitsets
(exemple)
Au lieu de:
function remove($path, $files = true, $directories = true, $links = true,
$executable = true)
{
if (!$files && is_file($path))
return false;
if (!$directories && is_dir($path))
return false;
if (!$links && is_link($path))
return false;
if (!$executable && is_executable($path))
return false;
// ...
}
remove("/tmp/removeMe", true, false, true, false); // WTF ?!
66. Ensembles – Avec des bitsets
(exemple)
Essayer:
define("REMOVE_FILES", 1 << 0);
define("REMOVE_DIRS", 1 << 1);
define("REMOVE_LINKS", 1 << 2);
define("REMOVE_EXEC", 1 << 3);
define("REMOVE_ALL", ~0); // Setting all bits
function remove($path, $options = REMOVE_ALL)
{
if (~$options & REMOVE_FILES && is_file($path))
return false;
if (~$options & REMOVE_DIRS && is_dir($path))
return false;
if (~$options & REMOVE_LINKS && is_link($path))
return false;
if (~$options & REMOVE_EXEC && is_executable($path))
return false;
// ...
}
remove("/tmp/removeMe", REMOVE_FILES | REMOVE_LINKS); // Much better :)
67. Ensembles: Conclusions
● Utilisez la clé et non la valeur lorsque vous utilisez
un array PHP.
● Utilisez QuickHash pour des ensembles d'entiers si
possible.
● Utilisez SplObjectStorage dès que vous travaillez
avec des objecs.
● N'utilisez par array_unique() / in_array() /
array_search() lorsque vous avez besoin d'un
ensemble !
68. Maps
● Une map est une collection de paires clé/valeur où
chaque clé est unique.
69. Maps – Avec un array
$map = array();
$map["ONE"] = 1;
$map["TWO"] = 2;
$map["THREE"] = 3;
// Merging maps:
array_merge($map1, $map2); // SLOW!
$map2 + $map1; // Fast :)
● N'utilisez pas array_merge() sur des maps.
71. Tas (Heap)
● Un tas est une structure basée sur un arbre dans
lequel les éléments sont ordonnés avec la clé la
plus grande (ou petite) au sommet et les plus
petites (ou grandes) comme feuilles.
72. Tas (Heap)
● Un tas est une structure basée sur un arbre dans
lequel les éléments sont ordonnés avec la clé la
plus grande (ou petite) au sommet et les plus
petites (ou grandes) comme feuilles.
73. Tas (Heap) – Avec un array
$heap = array();
$heap[] = 3;
sort($heap);
$heap[] = 1;
sort($heap);
$heap[] = 2;
sort($heap);
74. Tas (Heap) – Avec
Spl(Min|Max)Heap
$heap = new SplMinHeap;
$heap->insert(3);
$heap->insert(1);
$heap->insert(2);
75. Tas (Heap): Conclusions
● BEAUCOUP plus rapide que de devoir réordonner un
array à chaque insertion.
● Si vous n'avez pas besoin qu'une collection soit
ordonnée à chaque étape et que vous pouvez insérer
toutes les données en un coup et ensuite utilisez
sort(). Dans ce cas l'array est une bien meilleure
approche.
● SplPriorityQueue est très similaire, considérez qu'il
s'agit de la même chose que SplHeap mais où le tri est
fait sur la clé et non la valeur.
76. Filtre de Bloom
● Un filtre de Bloom est une structure probabiliste
efficace en terme d'espace permettant de tester
l'appartenance d'un élément à un ensemble.
● Les faux-positifs sont possibles, mais les faux-
négatifs ne le sont jamais !
● Package PECL : bloomy
77. Filtre de Bloom – Avec bloomy
// BloomFilter::__construct(int capacity [, double
error_rate [, int random_seed ] ])
$bloomFilter = new BloomFilter(10000, 0.001);
$bloomFilter->add("An element");
$bloomFilter->has("An element"); // true for sure
$bloomFilter->has("Foo"); // false, most probably
78. Autres projets apparentés
● SPL Types: Différents types implémentés comme
objet: SplInt, SplFloat, SplEnum, SplBool et
SplString http://pecl.php.net/package/SPL_Types
79. Autres projets apparentés
● SPL Types: Différents types implémentés comme
objet: SplInt, SplFloat, SplEnum, SplBool et
SplString http://pecl.php.net/package/SPL_Types
● Judy: Implémentation de Sparse dynamic arrays
http://pecl.php.net/package/Judy
80. Autres projets apparentés
● SPL Types: Différents types implémentés comme
objet: SplInt, SplFloat, SplEnum, SplBool et
SplString http://pecl.php.net/package/SPL_Types
● Judy: Implémentation de Sparse dynamic arrays
http://pecl.php.net/package/Judy
● Weakref: Implementation de « pointeurs faibles »
(Weak reference).
Permet de référencer un objet sans pour autant
empêcher le GC de pouvoir récupérer cet objet.
81. Conclusions
● Utilisez des structures de données appropriées.
Cela vous permet de garder un code propre et
optimal.
82. Conclusions
● Utilisez des structures de données appropriées.
Cela vous permet de garder un code propre et
optimal.
● Pensez à la complexité en termes de temps et
d'espaces impliquée par vos algorithmes.
83. Conclusions
● Utilisez des structures de données appropriées.
Cela vous permet de garder un code propre et
optimal.
● Pensez à la complexité en termes de temps et
d'espaces impliquée par vos algorithmes.
● Nommez vos variables de manière appropriée :
Utilisez « Map », « Set », « List », « Queue »,... afin de
décrire leur rôle et utilisation.
84. Merci
● N'oubliez pas de donner votre évaluation sur cette session sur :
http://joind.in/6446