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

Maitriser les structures de données PHP 102 - Forum Paris 2012

Maitriser les structures de données PHP 102 - Forum Paris 2012

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.

Patrick Allaert

June 07, 2012
Tweet

More Decks by Patrick Allaert

Other Decks in Technology

Transcript

  1. Patrick ALLAERT • Fondateur de Libereco Technologies • Travailles avec

    PHP/Linux depuis '98 • Core développeur eZ Publish • Auteur de l'extension PHP APM • @patrick_allaert • [email protected] • http://github.com/patrickallaert/ • http://patrickallaert.blogspot.com/
  2. APM

  3. APM

  4. Structures de données PHP natives • NULL (IS_NULL) • Booléens

    (IS_BOOL) • Entiers (IS_LONG) • Nombres à virgule flottante (IS_DOUBLE) • Chaine de caractères (IS_STRING) • Tableaux (IS_ARRAY, IS_CONSTANT_ARRAY) • Objets (IS_OBJECT) • Ressources (IS_RESOURCE) • Callable (IS_CALLABLE)
  5. Les structures de données sur Wikipedia • 2-3-4 tree •

    2-3 heap • 2-3 tree • AA tree • Abstract syntax tree • (a,b)-tree • Adaptive k-d tree • Adjacency list • Adjacency matrix • AF-heap • Alternating decision tree • And-inverter graph • And–or tree • Array • AVL tree • Beap • Bidirectional map • Bin • Binary decision diagram • Binary heap • Binary search tree • Binary tree • Binomial heap • Bit array • Bitboard • Bit field • Bitmap • BK-tree • Bloom filter • Boolean • Bounding interval hierarchy • B sharp tree • BSP tree • B-tree • B*-tree • B+ tree • B-trie • Bx-tree • Cartesian tree • Char • Circular buffer • Compressed suffix array • Container • Control table • Cover tree • Ctrie • Dancing tree • D-ary heap • Decision tree • Deque • Directed acyclic graph • Directed graph • Disjoint-set • Distributed hash table • Double • Doubly connected edge list • Doubly linked list • Dynamic array • Enfilade • Enumerated type • Expectiminimax tree • Exponential tree • Fenwick tree • Fibonacci heap • Finger tree • Float • FM-index • Fusion tree • Gap buffer • Generalised suffix tree • Graph • Graph-structured stack • Hash • Hash array mapped trie • Hashed array tree • Hash list • Hash table • Hash tree • Hash trie • Heap • Heightmap • Hilbert R-tree • Hypergraph • Iliffe vector • Image • Implicit kd-tree • Interval tree • Int • Judy array • Kdb tree • Kd-tree • Koorde • Leftist heap • Lightmap • Linear octree • Link/cut tree • Linked list • Lookup table • Map/Associative array/Dictionary • Matrix • Metric tree • Minimax tree • Min/max kd-tree • M-tree • Multigraph • Multimap • Multiset • Octree • Pagoda • Pairing heap • Parallel array • Parse tree • Plain old data structure • Prefix hash tree • Priority queue • Propositional directed acyclic graph • Quad-edge • Quadtree • Queap • Queue • Radix tree • Randomized binary search tree • Range tree • Rapidly-exploring random tree • Record (also called tuple or struct) • Red-black tree • Rope • Routing table • R-tree • R* tree • R+ tree • Scapegoat tree • Scene graph • Segment tree • Self-balancing binary search tree • Self-organizing list • Set • Skew heap • Skip list • Soft heap • Sorted array • Spaghetti stack • Sparse array • Sparse matrix • Splay tree • SPQR-tree • Stack • String • Suffix array • Suffix tree • Symbol table • Syntax tree • Tagged union (variant record, discriminated union, disjoint union) • Tango tree • Ternary heap • Ternary search tree • Threaded binary tree • Top tree • Treap • Tree • Trees • Trie • T-tree • UB-tree • Union • Unrolled linked list • Van Emde Boas tree • Variable-length array • VList • VP-tree • Weight-balanced tree • Winged edge • X-fast trie • Xor linked list • X-tree • Y-fast trie • Zero suppressed decision diagram • Zipper • Z-order
  6. Array: Le mensonge PHP Les “Arrays” PHP ne sont pas

    de vrais tableaux! Un tableau ressemble typiquement à: Data Data Data Data Data Data 0 1 2 3 4 5
  7. 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).
  8. 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: Data Data Data Data Data Head Tail Permet d'implémenter: Liste, Deque, File et Tas
  9. Array: Le mensonge PHP Les éléments d'un“Array” PHP peuvent à

    tout moment être accédés au moyen d'une clé (index).
  10. 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: Data Data Data Data Data Head Tail Bucket Bucket Bucket Bucket Bucket Bucket pointers array Bucket * 0 Bucket * 1 Bucket * 2 Bucket * 3 Bucket * 4 Bucket * 5 ... Bucket * nTableSize -1
  11. 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.”
  12. 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
  13. 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
  14. Structs – Avec un array $person = array( "firstName" =>

    "Patrick", "lastName" => "Allaert" );
  15. Structs – Avec une classe (Implémentation) class PersonStruct { public

    $firstName; public $lastName; public function __construct($firstName, $lastName) { $this->firstName = $firstName; $this->lastName = $lastName; } }
  16. 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 } }
  17. Structs – Avantages et inconvénients Array + Utilise moins de

    mémoire (PHP < 5.4) - Utilise plus de mémoire (PHP = 5.4) - Pas de type hinting - Structure flexible +|- Moins OO Class - Utilise plus de mémoire (PHP < 5.4) + Utilise moins de mémoire (PHP = 5.4) + Type hinting possible + Structure rigide +|- Plus OO
  18. (vrai) Tableaux • Un tableau est une collection de taille

    fixe dont les éléments sont tous identifiés par un index numérique.
  19. (vrai) Tableaux • Un tableau est une collection de taille

    fixe dont les éléments sont tous identifiés par un index numérique. Data Data Data Data Data Data 0 1 2 3 4 5
  20. (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
  21. (vrai) Tableaux – Avantages et inconvénients Array - Utilise plus

    de mémoire +|- Moins OO SplFixedArray + Utilise moins de mémoire +|- Plus OO
  22. 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.
  23. 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 Data Data Data Data Data Data Data Enqueue Dequeue
  24. 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
  25. 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
  26. 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é.
  27. 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 Data Data Data Data Data Data Data Push Pop
  28. 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
  29. 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
  30. Files/Piles – Avantages et inconvénients Array - Utilise plus de

    mémoire (overhead / entrée: 96 octets) - Pas de type hinting +|- Moins OO SplQueue / SplStack + Utilise moins de mémoire (overhead / entrée: 48 octets) + Type hinting possible +|- Plus OO
  31. 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.
  32. 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
  33. 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
  34. 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 True performance killers!
  35. Ensembles – Abus if ($value === "val1" || $value ===

    "val2" || $value === "val3"))) { // ... }
  36. 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
  37. Ensembles – Avec un array (types simples) • Attention :

    les clés d'un array PHP ne peuvent être que des entiers ou des strings ! $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
  38. 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
  39. 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 Store a reference of the object!
  40. 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
  41. Ensembles – Avec QuickHash (int) • Pas (encore?) d'opérations d'union/d'intersection/de

    complément. • Fonctionnalités intéressantes : (loadFrom|saveTo)(String|File) $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]);
  42. 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
  43. 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 ?!
  44. 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 :)
  45. 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 !
  46. Maps – Avec un array • N'utilisez pas array_merge() sur

    des maps. $map = array(); $map["ONE"] = 1; $map["TWO"] = 2; $map["THREE"] = 3; // Merging maps: array_merge($map1, $map2); // SLOW! $map2 + $map1; // Fast :)
  47. Maps multi-clés – Avec un array $map = array(); $map["ONE"]

    = 1; $map["UN"] =& $map["ONE"]; $map["UNO"] =& $map["ONE"]; $map["TWO"] = 2; $map["DEUX"] =& $map["TWO"]; $map["DUE"] =& $map["TWO"]; $map["UNO"] = "once"; $map["DEUX"] = "twice"; var_dump($map); /* array(6) { ["ONE"] => &string(4) "once" ["UN"] => &string(4) "once" ["UNO"] => &string(4) "once" ["TWO"] => &string(5) "twice" ["DEUX"] => &string(5) "twice" ["DUE"] => &string(5) "twice" } */
  48. 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.
  49. 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.
  50. Tas (Heap) – Avec un array $heap = array(); $heap[]

    = 3; sort($heap); $heap[] = 1; sort($heap); $heap[] = 2; sort($heap);
  51. 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.
  52. 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
  53. 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
  54. 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
  55. 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
  56. 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.
  57. 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.
  58. 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.
  59. Crédits Photos • Tuned car: http://www.flickr.com/photos/gioxxswall/5783867752 • London Eye Structure:

    http://www.flickr.com/photos/photographygal123/4883546484 • Cigarette: http://www.flickr.com/photos/superfantastic/166215927 • Heap structure: http://en.wikipedia.org/wiki/File:Max-Heap.svg • Drawers: http://www.flickr.com/photos/jamesclay/2312912612 • Stones stack: http://www.flickr.com/photos/silent_e/2282729987 • Tree: http://www.flickr.com/photos/drewbandy/6002204996