📜 ⬆️ ⬇️

Full collections in PHP

Not so long ago, when developing my project, an idea arose to implement full-fledged collections for storing objects of the same type, which, for convenience, resemble List <Type> in C #.
The idea is that collections containing objects of different types are different in themselves, and do not have, say, one unified type Collection . In other words, a collection of User objects is not the same as a collection of Book objects. Naturally, the first thought was to create different classes for collections ( UserCollection , BookCollection , ...). But the data approach does not provide the necessary flexibility, plus everything, you need to spend time declaring each such class.
After a bit of thinking, I implemented the dynamic creation of collection classes. It looks like this: the user creates a collection of objects of type Book, and the desired type BookCollection is created (that is, declared) automatically.

What I got in the end:

- Full TypeHinting created types of collections.
- Strong typing collections.
- It is possible to access the collection as an array as in C # (by implementing the ArrayAccess interface)
- Full iteration of the collection (possibility of use in any cycles).

Implementation


Collection factory


/** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  1. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  2. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  3. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  4. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  5. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  6. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  7. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  8. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  9. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  10. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  11. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  12. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  13. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  14. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  15. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  16. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  17. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  18. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  19. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  20. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  21. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  22. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  23. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  24. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  25. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  26. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  27. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  28. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  29. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  30. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
  31. /** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .
/** * * * @author [x26]VOLAND */ abstract class CollectionFactory { /** * . * * @param string $type * @return mixed */ public static function create($type) { $ class = $type . 'Collection' ; self::__create_class($ class ); $obj = new $ class ($type); return $obj; } /** * $class * * @param string $class * @return void */ private static function __create_class($ class ) { if ( ! class_exists($ class )) { eval( 'class ' . $ class . ' extends Collection { }' ); } } } * This source code was highlighted with Source Code Highlighter .

')

Collection class (describes behavior)


  1. / **
  2. * Collection class
  3. * Basic universal type, based on which collections will be created.
  4. *
  5. * @author [x26] VOLAND
  6. * /
  7. abstract class Collection implements IteratorAggregate, ArrayAccess, Countable {
  8. / **
  9. * The type of items stored in this collection.
  10. * @var string
  11. * /
  12. private $ __ type;
  13. / **
  14. * Object storage
  15. * @var array
  16. * /
  17. private $ __ collection = array ();
  18. // ------------------------------------------------ --------------------
  19. / **
  20. * Constructor.
  21. * Sets the type of elements that will be stored in this collection.
  22. *
  23. * @param string $ type Element type
  24. * @return void
  25. * /
  26. public function __construct ($ type) {
  27. $ this -> __ type = $ type;
  28. }
  29. // ------------------------------------------------ --------------------
  30. / **
  31. * Checks the type of object.
  32. * Prevents the addition to the collection of objects of someone else’s type.
  33. *
  34. * @param object $ object Object to check
  35. * @return void
  36. * @throws Exception
  37. * /
  38. private function __check_type (& $ object ) {
  39. if (get_class ($ object )! = $ this -> __ type) {
  40. throw new Exception ( 'Object of type' ' . get_class ($ object )
  41. . '`cannot be added to the collection of objects of type' ' . $ this -> __ type. '`' );
  42. }
  43. }
  44. // ------------------------------------------------ --------------------
  45. / **
  46. * Adds the objects passed in the arguments to the collection.
  47. *
  48. * @param object (s) Objects
  49. * @return mixed collection
  50. * /
  51. public function add ()
  52. {
  53. $ args = func_get_args ();
  54. foreach ($ args as $ object ) {
  55. $ this -> __ check_type ($ object );
  56. $ this -> __ collection [] = $ object ;
  57. }
  58. return $ this ;
  59. }
  60. // ------------------------------------------------ --------------------
  61. / **
  62. * Removes from the collection the objects passed in the arguments.
  63. *
  64. * @param object (s) Objects
  65. * @return mixed collection
  66. * /
  67. public function remove ()
  68. {
  69. $ args = func_get_args ();
  70. foreach ($ args as $ object ) {
  71. unset ($ this -> __ collection [array_search ($ object , $ this -> __ collection)]);
  72. }
  73. return $ this ;
  74. }
  75. // ------------------------------------------------ --------------------
  76. / **
  77. * Clears the collection.
  78. *
  79. * @return mixed collection
  80. * /
  81. public function clear () {
  82. $ this -> __ collection = array ();
  83. return $ this ;
  84. }
  85. // ------------------------------------------------ --------------------
  86. / **
  87. * Determines if the collection is empty.
  88. *
  89. * @return bool
  90. * /
  91. public function isEmpty () {
  92. return empty ($ this -> __ collection);
  93. }
  94. // ------------------------------------------------ --------------------
  95. / **
  96. * IteratorAggregate interface implementation
  97. * /
  98. / **
  99. * Returns an iterator object.
  100. *
  101. * @return CollectionIterator
  102. * /
  103. public function getIterator () {
  104. return new CollectionIterator ($ this -> __ collection);
  105. }
  106. // ------------------------------------------------ --------------------
  107. / **
  108. * Implementation of the ArrayAccess interface.
  109. * /
  110. / **
  111. * Sets an element of collection at the offset
  112. *
  113. * @param ineter $ offset Offset
  114. * @param mixed $ offset Object
  115. * @return void
  116. * /
  117. public function offsetSet ($ offset, $ object ) {
  118. $ this -> __ check_type ($ object );
  119. if ($ offset === NULL) {
  120. $ offset = max (array_keys ($ this -> __ collection)) + 1;
  121. }
  122. $ this -> __ collection [$ offset] = $ object ;
  123. }
  124. // ------------------------------------------------ --------------------
  125. / **
  126. * Find out if an item exists with a given key.
  127. *
  128. * @param integer $ offset Key
  129. * @return bool
  130. * /
  131. public function offsetExists ($ offset) {
  132. return isset ($ this -> __ collection [$ offset]);
  133. }
  134. // ------------------------------------------------ --------------------
  135. / **
  136. * Removes the item referenced by the $ offset key.
  137. *
  138. * @param integer $ offset Key
  139. * @return void
  140. * /
  141. public function offsetUnset ($ offset) {
  142. unset ($ this -> __ collection [$ offset]);
  143. }
  144. // ------------------------------------------------ --------------------
  145. / **
  146. * Returns an item by key.
  147. *
  148. * @param integer $ offset Key
  149. * @return mixed
  150. * /
  151. public function offsetGet ($ offset) {
  152. if (isset ($ this -> __ collection [$ offset]) === FALSE) {
  153. return NULL;
  154. }
  155. return $ this -> __ collection [$ offset];
  156. }
  157. // ------------------------------------------------ --------------------
  158. / **
  159. * Implementing the Countable Interface
  160. * /
  161. / **
  162. * Returns the number of items in the collection.
  163. *
  164. * @return integer
  165. * /
  166. public function count () {
  167. return sizeof ($ this -> __ collection);
  168. }
  169. }
* This source code was highlighted with Source Code Highlighter .


Examples of using



  1. <? php
  2. class BookStore {
  3. function addBooks (BookCollection $ books) {
  4. // implementation
  5. }
  6. function addMagazines (MagazineCollection $ magazines) {
  7. // implementation
  8. }
  9. function addGoods (Collection $ goods) {
  10. // If collection type is not important,
  11. // you can specify the base type of collection
  12. }
  13. }
  14. class Book {
  15. var $ id;
  16. function Book ($ id) {
  17. $ this -> id = $ id;
  18. }
  19. }
  20. class Magazine {
  21. var $ id;
  22. function Magazine ($ id) {
  23. $ this -> id = $ id;
  24. }
  25. }
  26. // Create a collection
  27. $ books = CollectionFactory :: create ( 'Book' );
  28. echo get_class ($ books); // BookCollection
  29. // Add objects to the collection:
  30. $ books-> add ( new Book (1), new Book (2));
  31. $ books-> add ( new Book (3)) -> add ( new Book (2));
  32. $ books [] = new Book (5);
  33. echo count ($ books); // five
  34. ...
  35. foreach ($ books as $ book) {
  36. echo $ book-> id;
  37. } // 12345
  38. ...
  39. $ books-> add ( new Magazine (1)); // Error (wrong type)
  40. ...
  41. $ magazines = CollectionFactory :: create ( 'Magazine' );
  42. $ magazines-> add ( new Magazine (1));
  43. ...
  44. $ bookStore = new BookStore ();
  45. $ bookStore-> addBooks ($ books); // Everything is good
  46. $ bookStore-> addBooks ($ magazines); // Error (wrong type)
  47. $ bookStore-> addMagazines ($ magazines); // Everything is good
  48. $ bookStore-> addGoods ($ books); // Everything is good
  49. $ bookStore-> addGoods ($ magazines); // Everything is good
  50. ?>
* This source code was highlighted with Source Code Highlighter .

Download source

Source: https://habr.com/ru/post/64840/


All Articles